EF/LINQ 如何在双向关系下包含子实体

7

环境

我正在使用基于Framework 4.0的Entity Framework 5。(这意味着我实际上使用的是EF 4.4)。 作为实体,我使用STE(自跟踪实体),因为我正在开发一个N-Tier应用程序。 我们采用数据库驱动方法,因为EF是在后期引入的。

背景

我有两个实体,它们都有彼此的导航属性。(EntityA具有指向EntityB的导航属性,而EntityB则具有指向EntityA的导航属性)。 关系是'EntityA > One-TO-Many > EntityB'。当我想通过LINQ表达式加载子实体时,我需要使用INCLUDE(STE => Eager Loading),因为我将通过多层传递所有数据。

代码

这是我的代码,用于调用具有其EntityB子项的EntityA。

using (var ctx = new MyEntities())
{
     var result = (from s in ctx.EntityA.Include("EntityB")
                   where s.Id = 11111
                   orderby s.TimeUpdated descending 
                   select s)
               .Take(10)
               .ToList();
     return result;
}

错误

System.StackOverflowException {当前线程处于堆栈溢出状态,无法评估表达式。}

如果我删除 'INCLUDE',则没有错误。我猜原因很简单。我想用子记录 EntityB 加载 EntityA,EntityB 记录每次都要加载其父记录 EntityA,而 EntityA ... 我想每个人都理解这里的无限循环。

我的解决方案或替代方案

  • 我进入我的 EDMX 文件并删除了 EntityB 中 EntityA 的导航属性。如果现在我想要加载有关 EntityA 的数据,同时我有一个 EntityB 可以使用。我需要进行单独的 DB 请求,并且我必须通过我的层传递 2 种不同的对象。
  • 避免使用 include,分别加载 EntityA 并将其推送到引用 EntityA 的我的 EntityB 的导航属性中。

问题

在我的情况下,是否有更好的替代方案或方法来解决这个问题?我应该继续使用我提出的一种替代方案吗?因为我希望有一个更好和更清洁的解决方案。

感谢您花时间阅读

Ian


1
对于你来说,这是一个非常好的(第一)问题,点个赞! - Ken D
我尝试在EF 5(Visual Studio 2012)中重现您的问题,但我没有收到任何错误。还有其他可能导致您的问题的原因吗?它是否与简单的POCO设置一起工作?(顺便说一句..我以前使用过STE,现在我真的想避免它们。您确定要使用STE吗?) - Wouter de Kort
我也无法重现错误(EF5,.NET 4.0)。您能否发布堆栈跟踪并可能擦除敏感数据? - Luc Bos
好的,我发现了下一个问题:我的项目是一个Webapp。当我在本地PC上运行Webapp并调用该方法时,会抛出此错误。 当我从测试类中完全相同的方法运行时,不会抛出任何错误。但是当Webapp抛出错误时,我可以通过删除“include”来修复它,因此我认为错误必须在这一行中。 我没有更多的堆栈跟踪,除了“mscorlib.dll中发生了未处理的System.StackOverflowException类型异常”。 - Segers-Ian
为了在stackoverflow之前中断,您可以在查询上设置一个带有条件的断点,例如“new StackTrace().FrameCount > 400”,然后您可以检查调用堆栈。我也完全同意Wouter的看法,STE很麻烦(我是吃过亏才学会的),您可以将实体映射到DTO,然后再映射回实体,并使用ApplyCurrentValues让上下文在保存时生成更改。 - Luc Bos
显示剩余3条评论
3个回答

1

我尝试在EF 5(Visual Studio 2012)中重现您的问题,但没有出现任何错误。还有其他可能导致您的问题的原因吗?它是否与简单的POCO设置一起工作?

我还想指出STE可能会让您感到非常头疼。我以前曾使用过STE,现在我真的很想避免它们。您确定要使用STE吗?

您可以使用普通的DTO代替STE。您将保留服务器上的丰富领域模型,并仅向客户端发送必要的数据。这样,您可以为每个用例创建定制的DTO,其中包含最少量的数据。


0

我来这里告诉你“你可以使用Include”,但显然这在此情况下没有帮助。

根据我在互联网上的阅读,通常我们怀疑(或有)无限循环案例时,有一些解决方法:

  1. 我们可以使用foreach通过手动加载子项来执行Load操作。
  2. 我们可以创建一个递归查询视图(并使用其实体)来自身进行解决。

  1. 无法应用加载操作,因为我的导航属性不是_EntityCollections<EntityA>,而是_TrackableCollection<EntityA>
  2. 不幸的是,这并不适用于我的情况。例如,我想轻松访问父实体(EntityA)并将其保存为我的EntityB字段。
我测试了'context.LoadProperty(EntityB, "EntityA")',但也生成了相同的StackOverflowException。感谢您的提示。
- Segers-Ian

-1

看这里

然而我已经安装了更新4,但仍无法进行调试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接