Linq-to-entities – Il metodo Include () non viene caricato

Se utilizzo un join, il metodo Include () non funziona più, ad esempio:

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 non è caricato

Senza il join, l’include () funziona

sottovento

AGGIORNAMENTO: In realtà ho aggiunto di recente un altro suggerimento che copre questo aspetto e fornisce una soluzione alternativa probabilmente migliore. L’idea è di posticipare l’uso di Include () fino alla fine della query, vedere questo per ulteriori informazioni: Suggerimento 22 – Come includere includere davvero


Vi è una limitazione nota in Entity Framework quando si utilizza Include (). Alcune operazioni non sono supportate con Include.

Sembra che tu abbia incontrato uno di questi limiti, per ovviare a questo dovresti provare qualcosa del genere:

 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}; 

Questo riporterà le Proprietà, e se la relazione tra entity framework e Proprietà è da uno a molti (ma non da molti a molti), scoprirai che ogni tipo anonimo risultante ha gli stessi valori in:

 anonType.Entity.Properties anonType.Properties 

Questo è un effetto collaterale di una funzionalità in Entity Framework chiamata fixup delle relazioni.

Vedere questo Suggerimento 1 nella mia serie di punte EF per ulteriori informazioni.

Prova questo:

 var query = (ObjectQuery)(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") 

Quindi qual è il nome della proprietà di navigazione su “Entity” che si riferisce a “Item.Member” (ovvero, è l’altra estremità della navigazione). Dovresti usare questo invece del join. Ad esempio, se ” quadro” aggiunge una proprietà denominata Membro con cardinalità di 1 e Membro ha una proprietà denominata Articoli con cardinalità di molti, è ansible eseguire questa operazione:

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

Sto indovinando le proprietà del tuo modello qui, ma questo dovrebbe darti un’idea generale. Nella maggior parte dei casi, l’utilizzo di join in LINQ su Entità è errato , poiché suggerisce che le proprietà di navigazione non sono configurate correttamente o non le si sta utilizzando.

Quindi, mi rendo conto che sono in ritardo per la festa qui, tuttavia ho pensato di aggiungere le mie conclusioni. Questo dovrebbe essere un commento sul post di Alex James, ma dato che non ho la reputazione che dovrà andare qui.

Quindi la mia risposta è: non sembra funzionare come vorreste. Alex James offre due soluzioni interessanti, tuttavia se le provate e controllate l’SQL, è orribile.

L’esempio a cui stavo lavorando è:

  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(); 

Questo segue il più semplice dei due esempi. Senza l’inclusione produce lo sql perfettamente rispettabile:

 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]) 

Ma con, 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 

Spazzatura totale Il punto chiave da notare qui è il fatto che restituisce la versione esterna unita della tabella che non è stata limitata da status = 1.

Ciò comporta la restituzione dei dati WRONG:

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

Si noti che lo stato di 2 viene restituito lì, nonostante la nostra restrizione. Semplicemente non funziona. Se ho sbagliato da qualche parte, sarei lieto di scoprirlo, visto che questo sta facendo beffe di Linq. Adoro l’idea, ma l’esecuzione non sembra essere utilizzabile al momento.


Per curiosità, ho provato il dbml di LinqToSQL piuttosto che l’edmx di LinqToEntities che ha prodotto il pasticcio sopra:

 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] 

Leggermente più compatto – clausola di conteggio strano, ma lo stesso totale FAIL totale.

Qualcuno in realtà ha mai usato questa roba in una vera e propria applicazione commerciale? Sto davvero cominciando a chiedermi … Per favore dimmi che mi sono perso qualcosa di ovvio, visto che mi piace davvero tanto Linq!

Prova il modo più prolisso per fare più o meno la stessa cosa ottenere gli stessi risultati, ma con più 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(); } } 

Hai ancora lo stesso risultato (inaspettato)?

EDIT : Modificata la prima frase, poiché non era corretta. Grazie per il commento puntatore!