2009-04-27 12 views
44

Jeśli użyć sprzężenia, Include() metoda nie jest już działa, np:LINQ do podmiotów - Include() metoda nie ładowanie

from e in dc.Entities.Include("Properties") 
join i in dc.Items on e.ID equals i.Member.ID 
where (i.Collection.ID == collectionID) 
select e 

e.Properties nie jest załadowany

Bez dołączyć, Include() działa

Lee

+0

Dlaczego tak sądzisz? Navent wartości po wykonaniu? – pocheptsov

+0

Zgaduję, że "Właściwości" nie są rzeczywistymi ciągami, które przechodzisz do Uwzględnij. Oznacza to, że pominąłeś najważniejszą część pytania. Ponadto, pytam, dlaczego w ogóle używasz join; właściwości nawigacji to na ogół poprawny sposób na przechodzenie przez relacje w ramach Entity Framework. –

+0

pocheptsov - Wiem, że właściwości nie zostały załadowane, ponieważ Proeprties.IsLoaded jest fałszywe Witam Craig - "Właściwości" to poprawny ciąg. Łączenie odbywa się na innych elementach właściwości nawigacji. Łączenie istnieje, ponieważ mam wartość właściwości obiektu Item (Collection.ID), ale chcę encji, która jest z nim powiązana. Lee –

Odpowiedz

54

AKTUALIZACJA: W rzeczywistości dodałem ostatnio kolejną wskazówkę, która to omawia i zapewnia alternatywne, prawdopodobnie lepsze rozwiązanie. Chodzi o to, aby opóźnić stosowanie Include() aż do końca kwerendy, zobacz więcej informacji: Tip 22 - How to make include really include


Nie jest znane ograniczenie w Entity Framework przy użyciu include(). Pewne operacje nie są obsługiwane z funkcją Uwzględnij.

Wygląda jak można biegać w jednym z tych ograniczeń, aby obejść ten problem należy spróbować coś takiego:

var results = 
    from e in dc.Entities //Notice no include 
    join i in dc.Items on e.ID equals i.Member.ID 
    where (i.Collection.ID == collectionID) 
    select new {Entity = e, Properties = e.Properties}; 

To przywróci Właściwości, a jeśli relacja między jednostką a właściwościami jeden do wielu (ale nie wiele do wielu) można zauważyć, że każdy wynikające typ anonimowy posiada te same wartości:

anonType.Entity.Properties 
anonType.Properties 

jest to efektem ubocznym funkcji w Entity Framework zwane relacjami fixup.

Zobacz ten Tip 1 w moim EF Tips series, aby uzyskać więcej informacji.

+0

świetna odpowiedź, dziękuję za pomoc – ChrisHDog

+1

Czy to nadal się dzieje? Jeśli używasz "wybierz nowy przedmiot {...};" instrukcja .Include() nie działa? – grimus

+0

@grimus, zawijanie całego zapytania w "Uwzględnij" nie wydaje się obecnie działać, gdy typ elementu utworzony przez zapytanie nie jest typem jednostki. Jednak pierwotna sugestia uzyskania wartości właściwości nawigacji w klauzuli 'select' nadal wydaje się działać, aby to obejść. – Sam

0

Spróbuj bardziej opisowy sposób na robić mniej więcej to samo uzyskać takie same wyniki, ale z bardziej datacalls:

var mydata = from e in dc.Entities 
      join i in dc.Items 
       on e.ID equals i.Member.ID 
      where (i.Collection.ID == collectionID) 
      select e; 

foreach (Entity ent in mydata) { 
    if(!ent.Properties.IsLoaded) { ent.Properties.Load(); } 
} 

Czy nadal otrzymujesz ten sam (nieoczekiwany) wynik?

EDIT: Zmieniono pierwsze zdanie, ponieważ było nieprawidłowe. Dzięki za komentarz do komentarza!

+0

To w żaden sposób nie jest to samo. Twój kod spowoduje zapytania n + 1 bazy danych, gdzie n to liczba pobranych wierszy. Uwzględnij wyniki w 1 kwerendzie bazy danych. –

+0

Wiem, że nie robię tego samego - to był niechlujny sposób powiedzenia, że ​​skończę z tymi samymi wynikami. Głównym powodem, aby to zrobić, było sprawdzenie, czy w ten sposób zostaną załadowane dowolne właściwości. Jeśli nie, problem nie jest prawdopodobny w składni .Include(), ale raczej w danych (tam, gdzie brakuje powiązanych rekordów właściwości, na przykład ...). –

+0

Witaj Tomas Po załadowaniu Właściwości za pomocą Properties.Load() ładuje się je poprawnie. Jeśli używam opcji Uwzględnij ("Właściwości") w zapytaniu, które nie zawiera sprzężenia, np.: od e in dc.Entities.Include ("Właściwości") gdzie (e.ID = identyfikator) wybierz e; działa poprawnie. Lee –

4

Jaka jest więc nazwa właściwości nawigacji na "Podmiot", która odnosi się do "Element.Member" (tj. Jest drugim końcem nawigacji). Powinieneś używać tego zamiast łączenia. Na przykład, jeśli „Podmiot” dodać właściwość o nazwie Użytkownik z liczności 1 i państwa miał właściwość o nazwie przedmioty o liczności wiele, można to zrobić:

from e in dc.Entities.Include("Properties") 
where e.Member.Items.Any(i => i.Collection.ID == collectionID) 
select e 

Zgaduję na właściwości Twój model tutaj, ale to powinno dać ci ogólny pomysł. W większości przypadków użycie sprzężenia LINQ do jednostek jest nieprawidłowe, ponieważ sugeruje, że albo właściwości nawigacyjne nie są poprawnie skonfigurowane, albo nie są używane.

20

Spróbuj tego:

var query = (ObjectQuery<Entities>)(from e in dc.Entities 
      join i in dc.Items on e.ID equals i.Member.ID 
      where (i.Collection.ID == collectionID) 
      select e) 

return query.Include("Properties") 
1

Tak, zdaję sobie sprawę, jestem późno na imprezę tu jednak pomyślałem, że mogę dodać moje odkrycia.To naprawdę powinno być komentarzem do postu Alexa Jamesa, ale ponieważ nie mam reputacji, będzie musiał tu pójść.

Tak więc moja odpowiedź brzmi: nie wydaje się działać tak, jak byś tego chciał. Alex James daje dwa ciekawe rozwiązania, jednak jeśli spróbujesz ich i sprawdzisz SQL, to jest okropne.

przykładzie I działa się na to:

 var theRelease = from release in context.Releases 
         where release.Name == "Hello World" 
         select release; 

     var allProductionVersions = from prodVer in context.ProductionVersions 
            where prodVer.Status == 1 
            select prodVer; 

     var combined = (from release in theRelease 
         join p in allProductionVersions on release.Id equals p.ReleaseID 
         select release).Include(release => release.ProductionVersions);    

     var allProductionsForChosenRelease = combined.ToList(); 

Wynika to prostsze od tych dwóch przykładów. Bez dołączania go produkuje zacnej sql:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name] 
    FROM [dbo].[Releases] AS [Extent1] 
    INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID] 
    WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status]) 

ale z, OMG:

SELECT 
[Project1].[Id1] AS [Id], 
[Project1].[Id] AS [Id1], 
[Project1].[Name] AS [Name], 
[Project1].[C1] AS [C1], 
[Project1].[Id2] AS [Id2], 
[Project1].[Status] AS [Status], 
[Project1].[ReleaseID] AS [ReleaseID] 
FROM (SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Id] AS [Id1], 
    [Extent3].[Id] AS [Id2], 
    [Extent3].[Status] AS [Status], 
    [Extent3].[ReleaseID] AS [ReleaseID], 
    CASE WHEN ([Extent3].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] 
    FROM [dbo].[Releases] AS [Extent1] 
    INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID] 
    LEFT OUTER JOIN [dbo].[ProductionVersions] AS [Extent3] ON [Extent1].[Id] = [Extent3].[ReleaseID] 
    WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status]) 
) AS [Project1] 
ORDER BY [Project1].[Id1] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC 

Całkowity śmieci. Należy zwrócić uwagę na fakt, że zwraca ona zewnętrzną połączoną wersję tabeli, która nie jest ograniczona przez status = 1.

Prowadzi to do danych BŁĘDNYCH zwracane:

Id Id1 Name  C1 Id2 Status ReleaseID 
2 1 Hello World 1 1 2  1 
2 1 Hello World 1 2 1  1 

Uwaga że status 2 jest zwrócony tam, pomimo naszych ograniczeń. To po prostu nie działa. Jeśli coś poszło nie tak, byłbym zachwycony, gdybym się dowiedział, jako że kpią sobie z Linq. Uwielbiam ten pomysł, ale wykonanie nie wydaje się w tej chwili możliwe.


Z ciekawości próbowałem dbml LinqToSql zamiast edmx LinqToEntities które produkowały bałagan powyżej:

SELECT [t0].[Id], [t0].[Name], [t2].[Id] AS [Id2], [t2].[Status], [t2].[ReleaseID], (
    SELECT COUNT(*) 
    FROM [dbo].[ProductionVersions] AS [t3] 
    WHERE [t3].[ReleaseID] = [t0].[Id] 
    ) AS [value] 
FROM [dbo].[Releases] AS [t0] 
INNER JOIN [dbo].[ProductionVersions] AS [t1] ON [t0].[Id] = [t1].[ReleaseID] 
LEFT OUTER JOIN [dbo].[ProductionVersions] AS [t2] ON [t2].[ReleaseID] = [t0].[Id] 
WHERE ([t0].[Name] = @p0) AND ([t1].[Status] = @p1) 
ORDER BY [t0].[Id], [t1].[Id], [t2].[Id] 

Nieco bardziej kompaktowy - dziwne klauzuli count, ale ogólnie takiej samej łącznej niepowodzeniem.

Czy ktoś kiedykolwiek użył tego w prawdziwej aplikacji biznesowej? Naprawdę zaczynam się zastanawiać ... Proszę, powiedz mi, że przegapiłem coś oczywistego, bo naprawdę chcę polubić Linqa!

Powiązane problemy