entity framework多个对象上下文

这个问题已经以50种不同的方式被问到了500个不同的时间……但是这里又一次,因为我似乎无法找到我正在寻找的答案:

我正在使用EF4和POCO代理。

答:我有一个从ObjectContext的一个实例获取的对象图。 该ObjectContext被释放。

B.我有一个从ObjectContext的另一个实例获取的对象。 ObjectContext也被处理掉了。

我想在A中使用B中的实体设置一堆相关的属性….类似于

foreach(var itemFromA in collectionFromA) { itemFromA.RelatedProperty = itemFromB; } 

当我这样做时,我得到了例外:

 System.InvalidOperationException occurred Message=The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects. Source=System.Data.Entity StackTrace: at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges) at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints) at System.Data.Objects.DataClasses.EntityReference`1.set_ReferenceValue(IEntityWrapper value) at System.Data.Objects.DataClasses.EntityReference`1.set_Value(TEntity value) at 

我想我需要将这些实体从ObjectContexts中分离出来,以便上述工作…问题是,当它处理时从我的ObjectContext中分离所有实体似乎会破坏图形。 如果我这样做:

 objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged) .Select(i => i.Entity).OfType().ToList() .ForEach(i => objectContext.Detach(i)); 

图中的所有关系似乎都未设置。

我怎样才能解决这个问题?

@Danny Varod是对的。 您应该为整个工作流使用一个ObjectContext 。 此外,因为您的工作流程似乎是包含多个窗口的一个逻辑function,所以它应该也可以使用单个演示者。 然后,您将遵循建议的方法:每个演示者的单个上下文。 您可以多次调用SaveChanges ,这样就不会破坏您的逻辑。

该问题的根源是众所周知的问题,即在POCO实体之上生成的动态代理的缺陷与POCO T4模板生成的Fixup方法相结合。 当您处理它们时,这些代理仍然会引用上下文。 因此,他们认为他们仍然依附于上下文,他们不能被附加到另一个上下文。 强制它们释放对上下文的引用的唯一方法是手动分离。 同时,一旦您从上下文中分离实体,它就会从相关的附加实体中删除,因为您不能在同一个图中混合使用附加实体和分离实体。

您调用的代码中实际上没有出现此问题:

 itemFromA.RelatedProperty = itemFromB; 

但是在Fixup方法触发的反向操作中:

 itemFromB.RelatedAs.Add(itemFromA); 

我认为解决这个问题的方法是:

  • 不要这样做,并为整个工作单元使用单个上下文 – 这是假设的用法。
  • 删除反向导航属性,以便Fixup方法不会触发该代码。
  • 不要将POCO T4模板与Fixup方法一起使用或修改T4模板以不生成它们。
  • 关闭这些操作的延迟加载和代理创建。 这将从您的POCO中删除动态代理,因此它们将独立于上下文。

要关闭代理创建和延迟加载,请使用:

 var context = new MyContext(); context.ContextOptions.ProxyCreationEnabled = false; 

您实际上可以尝试编写自定义方法来分离整个对象图,但正如您所说,它被问了500次而我还没有看到工作解决方案 – 除了对新对象图的序列化和反序列化。

我想你在这里有几个不同的选择,其中2个是:

  1. 在完成该过程之前保持上下文处于活动状态,仅使用1个上下文,而不是2。

  2. 一个。 在处理上下文#1之前,使用BinaryStreamer或ValueInjecter或AutoMapper等工具创建图的深层克隆。

    湾 合并从上下文#2到克隆图的更改。

    C。 保存后,将克隆图形中的更改合并到由新ObjectContext创建的图形中。


为了将来参考,这个MSDN博客链接可以帮助您决定在以下时间做什么: http : //blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse。 ASPX

我认为你不需要分离来解决问题。

我们做这样的事情:

 public IList GetContacts() { using(myContext mc = new mc()) { return mc.Contacts.Where(c => c.City = "New York").ToList(); } } public IList GetSales() { using(myContext mc = new mc()) { return mc.Sales.Where(c => c.City = "New York").ToList(); } } public void SaveContact(Contact contact) { using (myContext mc = new myContext()) { mc.Attach(contact); contact.State = EntityState.Modified; mc.SaveChanges(); } } public void Link() { var contacts = GetContacts(); var sales = GetSales(); foreach(var c in contacts) { c.AddSales(sales.Where(s => s.Seller == c.Name)); SaveContact(c); } } 

这允许我们提取数据,将其传递给另一层,让他们做他们需要做的任何事情,然后将其传回,我们更新或删除它。 我们使用单独的上下文(每个方法一个 (每个请求一个完成所有这些操作。

要记住的重要一点是,如果您使用IEnumerables,它们将被延迟执行。 这意味着在您进行计数或迭代之前,它们实际上并不会提取信息。 因此,如果你想在你的上下文之外使用它,你必须做一个ToList(),以便迭代它并创建一个列表。 然后你可以使用该列表。

编辑更新更清晰,感谢@ Nick的输入。

好的,我知道你的对象上下文早已消失。

但是让我们以这种方式看待它,entity framework实现工作单元概念,在其中它跟踪您在对象图中所做的更改,以便它可以生成与您所做的更改相对应的SQL。 如果不依赖于上下文,就无法应对变化。

如果您无法控制上下文,那么我认为您无法做任何事情。

否则有两种选择,

  1. 保持对象上下文的活动时间更长,例如用户登录等。
  2. 尝试使用自跟踪文本模板重新生成代理类,该模板将在断开连接状态下启用更改跟踪。

但即使是在自我跟踪的情况下,您仍然可能会遇到一些问题。