... но создание объекта занимает много времени, так как у меня есть записи в миллионах, так как в одной стране может быть много штатов, а в одном штате много городов.Так что я хочу, если есть способ сделать это с Linq.
Имейте в виду, LINQ оптимизирован для повторного использования, а не для быстрого кода.Внутренне LINQ будет использовать foreach
, что вызовет GetEnumerator()
и MoveNext()
.foreach
, который разработан специально для вашего решения, вероятно, будет быстрее, чем LINQ foreach
, и вы можете оптимизировать еще больше, вызывая перечисление себя (GetEnumerator
и MoveNext
).
Тем не менее, есливы хотите использовать LINQ всякий раз, когда вам нужны объекты со своими подобъектами (обычно с внешним ключом), например, школы со своими учениками, библиотеки со своими книгами, страны со своими государствами, Enumerable.Groupjoin - этопуть.
Таким образом, у вас есть три коллекции, использующие первичные ключи и иностранные ключи для указания друг на друга:
IEnumerable<Country> countries = ...
IEnumerable<State> states = ...
IEnumerable<City> cities = ...
И вы хотите, чтобы коллекция стран с их государствами, где каждыйШтат имеет свои города.
var result = countries.GroupJoin(states, // GroupJoin countries and states
country => country.Id, // from the country take the primary key
state => state.CountryId // from the state take the foreign key
(country, statesOfCountry) => new // from every country with all its states
{ // make one new object
Id = country.Id, // cointaining only the properties you plan to use
Name = country.Name,
...
States = ... // see below
}
Чтобы вычислить States of every country with their cities
, мы Groupjoin
statesOfCountry
коллекция с коллекцией cities
, при сопоставлении первичного и внешнего ключа:
Продолжая LINQ выше:
States = statesOfCountry.GroupJoin(cities, // Groupjoin states with cities
stateOfCountry => stateOfCountry.Id, // from every state take the Id
city => city.StateId, // from every city take the stateId
(stateOfCountry, citiesOfState) => new // again: when they match make a new object
{
// for performance: select only the properties yo actually plan to use
Id = stateOfCountry.Id,
Name = stateOfCountry.Name,
// not needed: you know it equals Country.Id:
// CountryId = stateOfCountry.CountryId,
Cities = citiesOfState.Select(city => new
{
// only the properties you plan to use
Id = city.Id,
Name = city.Name,
Location = city.Location,
// not needed, you already know the value:
// StateId = city.StateId,
}),
}
Приятно то, что вы создали только перечислимый объект, а именно: вы создали только то, что умеет перечислять.Вы еще не перечислили.Преимущество в том, что это очень быстро, и если во время перечисления вы решите, что вам не нужна какая-то информация, вам не нужно будет ее перечислять.
Например, как только вы начнете перечисление и захотитеигнорировать все города русских городов:
foreach (var country in result)
{
if (country.Name != "Russia")
ProcessCountry(country);
// else: ignore
Преимущество этого состоит в том, что групповое соединение российских городов не будет выполнено