2013-03-01 13 views
19

otrzymuję następujący wyjątek:zagnieżdżonych zapytań w Entity Framework

Zapytanie zagnieżdżona nie jest obsługiwany. Operation1 = 'Case' Operation2 = 'Collect'

z tego zapytania

var Games = context.Games.Select(a => new GameModel 
{ 
    Members = (a.Type == 1 ? (a.UsersInGames.Where(b => b.GameID == a.ID && b.StatusID == 1).Select(c => new Member 
    { 
     ID = c.UserID, 
     email = c.UserInfo.EmailAddress, 
     screenName = c.UserInfo.ScreenName 
    })) : 
    (a.Teams.Where(b => b.GameID == a.ID).SelectMany(b => b.UsersInTeams.Where(c => c.StatusID == 1)).Select(d => new Member 
    { 
     ID = d.UserID, 
     email = d.UserInfo.EmailAddress, 
     screenName = d.UserInfo.ScreenName 
    ))) 
}) 

kiedy nie obejmują stan w wyborze Członków, kwerenda działa poprawnie. Czy jest sposób, w jaki mogę wykonać warunkowe zapytanie?

+0

Jest to konieczne, aby wykonać zapytanie w inicjalizacji? –

+0

@NathanWhite Nie jest to konieczne. Chciałbym wiedzieć, jak używać warunkowego w zapytaniu. – yqit

Odpowiedz

23

Przeceniasz moc tłumaczenia LINQ na SQL. Nie wszystko można przetłumaczyć i nie ma na to ostrzeżenia kompilatora ze względu na sposób działania LINQ.

Zagnieżdżone kolekcje są zazwyczaj albo a) nieobsługiwane, albo b) kończą się okropnymi zapytaniami SELECT N + 1. To, o co poprosisz EF, to zwrócenie drzewa obiektów. SQL nie obsługuje wyników takich jak drzewa, więc napotkasz niedopasowanie impedancji obiektowo-relacyjnej i to boli.

Radzę pobrać zagnieżdżone dane kolekcji jako drugie, całkowicie oddzielne zapytanie. To pozwala na większą kontrolę i gwarantuje pracę.

Jako nieistotny węzeł boczny prawdopodobnie nie będzie można przekonać EF, aby używał operatora? Jest to bardzo trudne do przetłumaczenia. Pomyśl, jak napisałbyś to jako SQL - bardzo trudne i zawiłe.

+7

Myślę, że twój ostatni akapit na temat potrójnego operatora '?:' Jest bardziej istotny niż myślisz - właśnie dlatego otrzymałem ten sam wyjątek, co osoba pytająca. Dziękuję za odpowiedź. –

+0

To są typowe "problemy" przechodzące z 'Linq2Sql' (co pozwala ci wykonywać różne rodzaje zwariowanych tłumaczeń, których EF nie ma), ale hej, domyślam się, że poruszasz się częściowo ze względu na wydajność, więc musisz się pożegnać do niektórych okropnych instrukcji SQL, które wygenerował Linq2Sql. –

+0

@Simon_Weaver * nadal * utknąłem z L2S na dużej podstawie kodu, ponieważ EF nie może, po 8 latach przewagi czasowej, tłumaczyć rzeczy takie jak "DateTime.Date". L2S był naprawdę fajnym systemem i myślę, że wybrali niewłaściwego do wycofania. L2S ma również model dostawcy.Po prostu zaznaczyli członków jako prywatni (prawdopodobnie ze względu na czas i budżet, planowano v2). Do tej pory mam kilka skarg na generowanie SQL L2S, które nie miałyby zastosowania do EF. Chociaż EF generuje teraz całkiem dobry SQL. Byłbym zainteresowany słuchaniem twoich myśli. – usr

3

Zmierzyłem się z tym samym problemem. Rozwiązaniem było obciążenia zarówno wyniki i ustalić, co do korzystania po zapytaniu (wiem, że ma wadę wydajności), ale przynajmniej można zrobić go tymczasowo, jeśli termin atakuje cię:

Na stronie LINQ

var Games = context.Games.Select(a => new GameModel 
     { 
      // carries type1 results 
      Members = a.UsersInGames.Where(b => b.GameID == a.ID && b.StatusID == 1).Select(c => new Member 
      { 
       ID = c.UserID, 
       email = c.UserInfo.EmailAddress, 
       screenName = c.UserInfo.ScreenName 
      })), 

      //You need to create this temporary carrier to carry type 2 results 
      MembersOfType2 = a.Teams.Where(b => b.GameID == a.ID).SelectMany(b => b.UsersInTeams.Where(c => c.StatusID == 1)).Select(d => new Member 
       { 
        ID = d.UserID, 
        email = d.UserInfo.EmailAddress, 
        screenName = d.UserInfo.ScreenName 
       }))) 
      }) 
     } 

Po tym może pętla Games i dokonać przyporządkowania Members = MembersOfType2 jeśli Type == 1 dla pewnej gry.

9

Wygląda Linq do EF nie obsługuje następujące

context.Games.Select(g => new 
{ 
    Field = g.IsX? queryable1 : queryable2 
}); 

Ale oto hack można użyć, aby zmusić go do pracy:

context.Games.Select(g => new 
{ 
    Field = queryable1.Where(q => g.IsX) 
       .Concat(queryable2.Where(q => !g.IsX)) 
}); 
+0

Nie nazwałbym tego "hackem", w zależności od tego, co jest po, może to być najmilszy sposób "mówienia" :-) –

+0

Potrzebowałem zrobić resultset sortuj w EF przez konkretny obiekt na liście właściwości nawigacji. Chciała uzyskać bieżący miesiąc, ale jeśli to nie przyniosło rezultatów, chcieliśmy zwrócić pierwszy miesiąc. To było naiwnie coś w stylu ... expr = x => (x.subset.Where (y => currentmonth) .Count()> 0? X.subset.Where (y => currentmonth): x.subset. OrderBy (y => miesiąc)). FirstOrDefault(). Właściwość Użyłem tego kodu do przekonwertowania na poniższe i wszystko działało idealnie i zostało przekonwertowane na SQL. x => (x.subset.Where (y => currentmonth) .Concat (x.subset.OrderBy (y => miesiąc))). FirstOrDefault(). Właściwość; –