2009-07-06 3 views
21

Я чувствовал, что следующее должно быть возможным. Я просто не знаю, какой подход принять.условно включить в linq для сущностей?

Что бы я хотел сделать, это использовать метод include для формирования моих результатов, т. Е. Определить, как далеко по объективному графу перемещаться. но ... Я бы хотел, чтобы этот обход был условным.

something like... 

dealerships 
    .include(d => d.parts.where(p => p.price < 100.00)) 
    .include(d => d.parts.suppliers.where(s => s.country == "brazil")); 

Я понимаю, что это не действует LINQ, на самом деле, что это ужасно неправильно, но по сути я ищу какой-нибудь способ, чтобы построить дерево выражения, которая будет возвращать фасонных результаты, эквивалентные ...

select * 
from dealerships as d 
outer join parts as p on d.dealerid = p.dealerid 
    and p.price < 100.00 
outer join suppliers as s on p.partid = s.partid 
    and s.country = 'brazil' 

с упором на условия соединения.

Я чувствую, что это было бы довольно прямолинейно с esql, но моим предпочтением было бы строить деревья выражений на лету.

как всегда, благодарен за любые советы или рекомендации

+1

Вы когда-нибудь находили решение этого вопроса? У меня та же проблема. –

+0

Пока нет, но я остаюсь заинтересованным и буду продолжать преследовать ... – tim

+0

Я искал то же самое –

ответ

15

Это должно сделать трюк:

using (TestEntities db = new TestEntities()) 
{ 
    var query = from d in db.Dealership 
       select new 
       { 
        Dealer = d, 
        Parts = d.Part.Where 
        (
         p => p.Price < 100.0 
          && p.Supplier.Country == "Brazil" 
        ), 
        Suppliers = d.Part.Select(p => p.Supplier) 
       }; 

    var dealers = query.ToArray().Select(o => o.Dealer); 
    foreach (var dealer in dealers) 
    { 
     Console.WriteLine(dealer.Name); 
     foreach (var part in dealer.Part) 
     { 
      Console.WriteLine(" " + part.PartId + ", " + part.Price); 
      Console.WriteLine 
       (
       " " 
       + part.Supplier.Name 
       + ", " 
       + part.Supplier.Country 
       ); 
     } 
    } 
} 

Этот код даст вам список Дилерский каждый из которых содержит отфильтрованный список деталей. Каждая часть ссылается на Поставщика. Интересная часть состоит в том, что вам нужно создать анонимные типы в выбранном порядке. В противном случае свойство Part объектов Dealership будет пустым.

Кроме того, вы должны выполнить инструкцию SQL, прежде чем выбирать дилеров из запроса. В противном случае свойство Части дилеров снова будет пустым.Вот почему я поставил вызов ToArray() в следующей строке:

var dealers = query.ToArray().Select(o => o.Dealer); 

Но я согласен с Дарреном, что это не может быть то, что пользователи вашей библиотеки ожидают.

+2

Замечание об этом, я пробовал это, и он не работал на начальном этапе. В конце концов я обнаружил, что включил Lazy Loading, в результате чего это не сработало. Как только я отключил ленивую загрузку, это работало как шарм. Спасибо, Якоб! – msmucker0527

+5

Это требует, чтобы вы возвращали анонимный тип вместо необработанного типа с фактическими ссылками. Это «работает», но оставляет мне желание вернуть исходный объект с фактическим объектом коллекции, отфильтрованным до того, что я действительно хотел вернуть. Анонимный тип возврата работает уверенно ... но на самом деле это не действительно желаемое решение. – VulgarBinary

+0

@VulgarBinary вы можете вернуть типизированный список таким образом: 'var dealers = query.ToArray(). Выберите (o => o.Dealer) .ToList();' Он просто работает! –

1

Могу ли я что-то отсутствует, или не вы просто ищете Any ключевое слово?

var query = dealerships.Where(d => d.parts.Any(p => p.price < 100.00) || 
           d.parts.suppliers.Any(s => s.country == "brazil")); 
+2

Я так не думаю, что, как я понимаю, это вернет дилерские центры, где были части и поставщики, которые встретили условия, а не возвращать все представительства, все части, которые составляют менее 100, и все поставщики в Бразилии. Я понимаю, что это должно быть внешнее соединение. я думаю, что я пытаюсь сделать, это обрезать дерево результатов, а не фильтровать узлы верхнего уровня на основе значений по дереву. – tim

6

Вы уверены, что это то, что вы хотите? Единственная причина, по которой я спрашиваю, когда вы добавляете фильтр на Parts off of Dealerships, ваши результаты больше не являются дилерскими центрами. Вы имеете дело с особыми объектами, которые по большей части очень близки к Dealerships (с теми же свойствами), но значение свойства «Parts» отличается. Вместо того, чтобы быть отношениями между Дилерами и частями, это отфильтрованные отношения.

Или, другими словами, если я тяну дилерский из ваших результатов и передается методу я написал, а затем в моем методе я называю:

var count = dealership.Parts.Count(); 

Я ожидаю, чтобы получить частей, а не отфильтрованных частей из Бразилии, где цена составляет менее 100 долларов США.

Если вы не используете объект дилера, чтобы передавать отфильтрованные данные, это становится очень простым. Он становится таким же простым, как:

var query = from d in dealerships 
       select new { DealershipName = d.Name, 
CheapBrazilProducts = dealership.Parts.Where(d => d.parts.Any(p => p.price < 100.00) || d.parts.suppliers.Any(s => s.country == "brazil")) }; 

Если я просто должен был получить отфильтрованные наборы, как вы спросили, я бы, вероятно, использовать технику я уже упоминал выше, а затем использовать инструмент как Automapper скопировать отфильтрованные результаты мой анонимный класс для реального класса. Это не невероятно элегантно, но оно должно работать.

Я надеюсь, что это поможет! Это была интересная проблема.

+0

Спасибо Darren Я согласен в том, что идентичность объекта! Я также обеспокоен тем, что именно поэтому это не может быть поддержано EF. То, что я действительно пытаюсь сделать здесь разобрать строку запроса, например http://carpartsdb.com/dealerships/parts(price <100)/поставщики (s.country == БРАЗИЛИЯ) в выражение запроса и проверить его на EF, выложите в пользовательскую стратегию сериализации xml и убедитесь, что у вас есть RestQL Engine (спокойный язык запросов). Я не слишком привязан к EF, но хочу иметь модели абстракции и деревья выражений, а EF - и не хочу отклоняться слишком далеко от стека MS! – tim

+0

sorry darren, см. Этот текст в дальнейшем ответе, где он будет более читабельным! – tim

0

Да, это то, что я хотел сделать. Думаю, что следующая версия Data Services будет иметь возможность делать именно эти запросы LINQ to REST, которые были бы замечательными в то время, когда я просто переключился на загрузку обратного и включил связанные объект, который будет загружен несколько раз, но в теории это просто нужно загрузить один раз в первом Включает как в этом коде

return this.Context.SearchHistories.Include("Handle") 
    .Where(sh => sh.SearchTerm.Contains(searchTerm) && sh.Timestamp > minDate && sh.Timestamp < maxDate); 

, прежде чем я пытался загрузить для любых Берите searchHistories, которые соответствовали логике, но не знает, как использовать логику Include, которую вы опубликовали, поэтому в среднем я думаю, что обратный поиск будет не столь грязным решением.

0

Я знаю, что это может работать с одним Include. Никогда не тестируйте с двумя включенными, но стоит попробовать:

dealerships 
    .Include(d => d.parts) 
    .Include(d => d.parts.suppliers) 
    .Where(d => d.parts.All(p => p.price < 100.00) && d.parts.suppliers.All(s => s.country == "brazil")) 
Смежные вопросы