2010-04-20 3 views
0

У меня есть пара таблиц, в которых есть одно-много отношений. Предположим, у меня есть таблица «Страна», таблица «Штат» с FK для страны и стол «Город» с FK для штата.LINQ to Entites: Выполнение счета по отношениям один-ко-многим

Я хотел бы быть в состоянии создать подсчет всех городов для данной страны, а также количество городов, основанных на фильтре - что-то вроде:

foreach(var country in Model.Country) { 
    total = country.State.All().City.All().Count() ; 
    filtered = country.State.All().City.Any(c=>c.field == value).Count(); 
} 

Очевидно, что это не работа - есть ли способ сделать это?

Update:

Я итерацию через объекты:

foreach (var item in Model) { 

     ... other stuff in here ... 

     int tot = 0; 
     int filtered = 0; 
     foreach (var state in item.State) 
     { 
     foreach (var city in state.City) 
     { 
      tot++; 
      if (city.Field == somevalue) 
      filtered ++; 
     } 
     } 

     ... other stuff in here ... 

    } 

, но это не кажется очень элегантно.

Update: @AD есть несколько предложений, но то, что работает, чтобы решить эту проблему было:

int tot = item.States.Sum(s=>s.City.Count); 
int filtered = item.States.Sum(s=>s.City.Where(c=>c.Field == somevalue).Count()); 

ответ

1

Вы можете попробовать, если вы уже имеете givenCountry и значение переменной заселена:

int total = EntityModel.CitySet.Where(it => it.State.Country.ID == givenCountry.ID).Count(); 

Выше, вы берете весь набор городов (EntityMode.CitySet). Этот набор содержит все города во всех штатах во всех странах. Проблема становится: какой подмножество этих городов находится в стране «данной страны»? Чтобы понять это, вы примените метод Where() ко всему набору, и вы сравниваете идентификатор стран, чтобы узнать, совпадают ли они. Однако, поскольку город знает только, в каком государстве он находится (а не в стране), вам сначала нужно ссылаться на его состояние (это государство). it.State ссылается на объект состояния, и этот объект имеет свойство Country, которое будет ссылаться на страну. Затем он. Государство. Страна ссылается на страну, в которой она находится, и «она» - это город, создающий связь между городом и деревней.

Обратите внимание, что вы могли бы сделать это реверс, а также с

int total = givenCountry.Sum(c => c.States.Sum(s.Cities.Count())) 

Однако, здесь вам придется убедиться, что givenCountry имеет свою коллекцию Штаты загружены в память, а также, что каждое государство имеет свою коллекцию городов загружен. Это связано с тем, что вы используете Linq-to-Entities на загруженном объекте, а не в объекте экземпляра Entity Framework, это было в первом примере.Существует способ для изготовления последнего запроса использовать рамочный объект объект однако:

int total = EntityModel.CountrySet.Where(c => c.ID == givenCountry.ID).Sum(c => c.States.Sum(s.Cities.Count())) 

Что касается количества городов с конкретной областью, вы такой же подход с Where (вызовом):

int filtered = EntityModel.CitySet.Where(it => it.field == value).Count(); 
+0

Проблема в том, что linq для объектов не работает таким образом. Моя модель представляет собой сборник стран, а страна не имеет собственности города - у нее есть коллекция государств, и у каждого штата есть коллекция Сити. – chris

+0

Если в стране имеется свод государств, то в ответ на это государство имеет единую страну, к которой она присоединена. То же самое касается государств и городов. Таким образом, это означает, что из города вы можете добраться до государства, а затем до страны. Конечно, предполагается, что вы работаете с Entity Framework, и вы используете отношения Entities (построенные либо из внешних ключей в БД, либо вручную из Model Viewer). Если вы создали объект Country/State/City вручную или у другого поставщика модели, тогда зависимость будет зависеть от тех моделей, которые вам необходимо предоставить. – ADB

+0

Использование EF и asp.net MVC 1.0. Модель содержит IEnemurable , и отношения есть. Проблема с вашим решением заключается в том, что у страны нет собственности на навигацию по городу - просто коллекция государств. – chris

0

Вы должны явно загружать детей в Entity Framework. Если вы загрузите всех детей, вы сможете получить счет просто отлично.

IEnumberable<Country> countries = Model.Country.Include("State"); 
total = countries[i].State.Count(); 

Предполагая, что итерация по всем странам важна. В противном случае, почему бы не просто запросить город, отфильтрованный государством и страной?

В вашем штате Foreach вы просто должны быть в состоянии сделать

tot += state.City.Where(x=> x.Field == value).Count(); 
+0

В моей модели есть все объекты, загруженные - я повторяю их и отображаю детали, но мне нужна определенная статистика («4/7 городов в ..»). – chris

+0

Если он полностью загружен, просто вставьте свой цикл, итерации через каждое состояние вместо выполнения состояний. All() –

+0

Я просто обновил свой вопрос, чтобы показать, как работает итерация. Тем не менее, это выглядит довольно не изящно. – chris

0

Почему бы вам не повернуть его вспять?

foreach(var country in Model.Country) { 
    var city = Model.State.Where(x=>x.StateID==country.State.StateID).Select(x=>City) 
    total = city.Count(); 
    filtered = city.All(c=>c.field == value).Count(); 
}