Linq-to-entities - Include()方法未加载

时间:2009-04-27 16:32:07

标签: linq entity-framework

如果我使用连接,则Include()方法不再有效,例如:

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未加载

没有连接,Include()可以正常工作

5 个答案:

答案 0 :(得分:54)

更新:实际上我最近添加了另一个提示,涵盖了这一点,并提供了另一种可能更好的解决方案。我们的想法是延迟使用Include()直到查询结束,有关详细信息,请参阅此内容:Tip 22 - How to make include really include


使用Include()时,实体框架存在已知限制。 Include不支持某些操作。

看起来你可能遇到过这些限制的问题,为了解决这个问题你应该尝试这样的事情:

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

这将带回属性,如果实体和属性之间的关系是一对多(但不是多对多),您会发现每个结果匿名类型具有相同的值:

anonType.Entity.Properties
anonType.Properties

这是实体框架中一项称为关系修正的功能的副作用。

有关详细信息,请参阅我的Tip 1中的EF Tips series

答案 1 :(得分:20)

试试这个:

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

答案 2 :(得分:4)

那么“实体”上与“Item.Member”相关的导航属性的名称是什么(即导航的另一端)。您应该使用此而不是连接。例如,如果“entity”添加一个名为Member的属性,其基数为1,而Member有一个名为Items的属性,其基数为多,则可以这样做:

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

我在这里猜测你的模型的属性,但这应该给你一般的想法。 在大多数情况下,在LINQ to Entities中使用连接是错误的,因为它表明您的导航属性设置不正确,或者您没有使用它们。

答案 3 :(得分:1)

所以,我意识到我在这里参加派对很晚,但是我想我会加上我的发现。这应该是对亚历克斯詹姆斯的帖子的评论,但由于我没有声誉,所以必须去这里。

所以我的答案是:它似乎根本无法发挥作用。 Alex James提供了两个有趣的解决方案,但是如果你尝试它们并检查SQL,那就太可怕了。

我正在研究的例子是:

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

这遵循两个例子中较简单的一个。没有包含它会产生完全可敬的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])

但是,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

垃圾总量。这里要注意的关键点是它返回表的外连接版本,该版本不受status = 1的限制。

这会导致返回错误的数据:

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

请注意,尽管我们有限制,但仍会在那里返回2的状态。它根本不起作用。 如果我在某个地方出错了,我会很高兴发现,因为这是对Linq的嘲弄。我喜欢这个想法,但目前执行似乎并不可用。


出于好奇,我尝试了LinqToSQL dbml,而不是产生上述混乱的LinqToEntities edmx:

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]

略微更紧凑 - 怪异的计数条款,但整体相同的总失败。

有没有人在真实的商业应用程序中使用过这些东西?我真的开始怀疑...... 请告诉我,我错过了一些明显的东西,因为我真的很想要Linq!

答案 4 :(得分:-1)

尝试更详细的方法或多或少做同样的事情获得相同的结果,但有更多的数据通道:

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

您是否仍然得到相同(意外)的结果?

编辑:更改了第一句,因为它不正确。感谢指针评论!