简体   繁体   English

实体框架多对象上下文

[英]Entity Framework Multiple Object Contexts

This question has been asked 500 different times in 50 different ways...but here it is again, since I can't seem to find the answer I'm looking for: 这个问题已经以50种不同的方式被问了500次不同的时间...但是这里又是一个问题,因为我似乎找不到想要的答案:

I am using EF4 with POCO proxies. 我正在将EF4与POCO代理一起使用。

A. I have a graph of objects I fetched from one instance of an ObjectContext. 答:我有一个从ObjectContext的一个实例获取的对象图。 That ObjectContext is disposed. 该ObjectContext被处置。

B. I have an object I fetched from another instance of an ObjectContext. B.我有一个从ObjectContext的另一个实例中获取的对象。 That ObjectContext has also been disposed. 该ObjectContext也已处置。

I want to set a related property on a bunch of things from A using the entity in B....something like 我想使用B中的实体在A上的一堆东西上设置相关属性...类似

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

When I do that, I get the exception: 当我这样做时,我得到一个例外:

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 

I guess I need to detach these entities from the ObjectContexts when they dispose in order for the above to work... The problem is, detaching all entities from my ObjectContext when it disposes seems to destroy the graph. 我猜想我需要在处理这些实体时从ObjectContext中分离这些实体,以使上述工作正常...问题是,在处理它时从我的ObjectContext中分离所有实体似乎会破坏图形。 If I do something like: 如果我做类似的事情:

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

All the relations in the graph seem to get unset. 图中的所有关系似乎都不确定。

How can I go about solving this problem? 我该如何解决这个问题?

@Danny Varod is right. @Danny Varod是正确的。 You should use one ObjectContext for the whole workflow. 您应该在整个工作流程中使用一个ObjectContext Moreover because your workflow seems as one logical feature containing multiple windows it should probably also use single presenter. 此外,由于您的工作流程似乎是包含多个窗口的一项逻辑功能,因此它可能也应使用单个演示者。 Then you would follow recommended approach: single context per presenter. 然后,您将遵循推荐的方法:每个演示者使用单个上下文。 You can call SaveChanges multiple times so it should not break your logic. 您可以多次调用SaveChanges ,这样就不会破坏您的逻辑。

The source of this issue is well known problem with deficiency of dynamic proxies generated on top of POCO entities combined with Fixup methods generated by POCO T4 template. 此问题的根源是众所周知的问题,即与POCO T4模板生成的Fixup方法结合使用时,在POCO实体顶部生成的动态代理不足。 These proxies still hold reference to the context when you dispose it. 当您处理它们时,这些代理仍然保留对上下文的引用。 Because of that they think that they are still attached to the context and they can't be attached to another context. 因此,他们认为它们仍附加在上下文中,而不能附加在另一个上下文中。 The only way how to force them to release the reference to the context is manual detaching. 强制它们释放对上下文的引用的唯一方法是手动分离。 In the same time once you detach an entity from the context it is removed from related attached entities because you can't have mix of attached and detached entities in the same graph. 同时,一旦您从上下文分离实体,该实体就会从相关的附加实体中移除,因为您不能在同一图中混合使用附加实体和分离实体。

The issue actually not occures in the code you call: 您调用的代码中实际上没有发生此问题:

itemFromA.RelatedProperty = itemFromB;

but in the reverse operation triggered by Fixup method: 但是在Fixup方法触发的反向操作中:

itemFromB.RelatedAs.Add(itemFromA);

I think the ways to solve this are: 我认为解决此问题的方法是:

  • Don't do this and use single context for whole unit of work - that is the supposed usage. 不要这样做,而是将单个上下文用于整个工作单元-这就是假定的用法。
  • Remove reverse navigation property so that Fixup method doesn't trigger that code. 删除反向导航属性,以便Fixup方法不会触发该代码。
  • Don't use POCO T4 template with Fixup methods or modify T4 template to not generate them. 不要将POCO T4模板与Fixup方法一起使用,也不要修改T4模板以不生成它们。
  • Turn off lazy loading and proxy creation for these operations. 关闭这些操作的延迟加载和代理创建。 That will remove dynamic proxies from your POCOs and because of that they will be independent on the context. 这将从您的POCO中删除动态代理,因此,它们将与上下文无关。

To turn off proxy creation and lazy loading use: 要关闭代理创建和延迟加载,请使用:

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

You can actually try to write custom method to detach the whole object graph but as you said it was asked 500 times and I haven't seen working solution yet - except the serialization and deserialization to the new object graph. 您实际上可以尝试编写自定义方法来分离整个对象图,但是正如您所说的,它被问了500次,我还没有看到有效的解决方案-除了序列化和反序列化到新对象图之外。

I think you have a few different options here, 2 of them are: 我认为您在这里有几个不同的选择,其中两个是:

  1. Leave context alive until you are done with the process, use only 1 context, not 2. 使上下文保持活动状态,直到完成该过程为止,仅使用1个上下文,而不是2个。

  2. a. 一种。 Before disposing of context #1, creating a deep clone of graph, using BinaryStreamer or a tool such as ValueInjecter or AutoMapper. 在处置上下文1之前,请使用BinaryStreamer或ValueInjecter或AutoMapper等工具创建图的深层克隆。

    b. b。 Merge changes from context #2 into cloned graph. 将上下文2中的更改合并到克隆的图中。

    c. C。 Upon saving, merge changes from cloned graph into graph created by new ObjectContext. 保存后,将克隆图的更改合并到新ObjectContext创建的图中。


For future reference, this MSDN blogs link can help decide you decide what to do when: http://blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse.aspx 为了将来参考,该MSDN博客链接可以帮助您决定何时决定做什么: http : //blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse。 aspx

I don't think you need to detach to solve the problem. 我认为您不需要解决这个问题。

We do something like this: 我们做这样的事情:

public IList<Contact> GetContacts()
{
  using(myContext mc = new mc())
  {
    return mc.Contacts.Where(c => c.City = "New York").ToList();
  }
}

public IList<Sale> 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);
   }
}

This allows us to pull the data, pass it to another layer, let them do whatever they need to do, and then pass it back and we update or delete it. 这使我们能够提取数据,将其传递到另一层,让他们做任何需要做的事情,然后将其传递回去,以便我们进行更新或删除。 We do all of this with a separate context (one per method) (one per request). 我们使用单独的上下文 (每个方法 一个 (每个请求一个 )来 完成所有这些操作。

The important thing to remember is, if you're using IEnumerables, they are deferred execution. 要记住的重要一点是,如果您使用的是IEnumerable,则会推迟执行它们。 Meaning they don't actually pull the information until you do a count or iterate over them. 意味着在您对它们进行计数或迭代之前,它们实际上不会提取信息。 So if you want to use it outside your context you have to do a ToList() so that it gets iterated over and a list is created. 因此,如果要在上下文之外使用它,则必须执行ToList(),以便对其进行迭代并创建一个列表。 Then you can work with that list. 然后,您可以使用该列表。

EDIT Updated to be more clear, thanks to @Nick's input. 编辑由于@Nick的输入,更新后变得更加清晰。

Ok I get it that your object context has long gone. 好的,我知道您的对象上下文已经消失了。

But let's look at it this way, Entity Framework implements unit of work concept, in which it tracks the changes you are making in your object graph so it can generate the SQL corresponding to the changes you have made. 但是,让我们以这种方式来看一下,Entity Framework实现了工作单元概念,在其中它跟踪您在对象图中进行的更改,以便它可以生成与您所做的更改相对应的SQL。 Without attached to context, there is no way it can tack changes. 如果不依赖上下文,就无法应对变化。

If you have no control over context then I don't think there is anything you can do. 如果您无法控制上下文,那么我认为您无能为力。

Otherwise there are two options, 否则,有两个选择,

  1. Keep your object context alive for longer lifespan like session of user logged in etc. 使对象上下文保持活动状态以延长使用寿命,例如用户会话登录等。
  2. Try to regenerate your proxy classes using self tracking text template that will enable change tracking in disconnected state. 尝试使用自我跟踪文本模板重新生成代理类,该模板将在断开状态下启用更改跟踪。

But even in case of self tracking, you might still get little issues. 但是,即使进行自我跟踪,也可能会遇到一些小问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 实体框架 - 跨多个上下文在内存中缓存对象 - Entity Framework — caching an object in memory across multiple contexts 将相同的对象附加到Entity Framework 6中的不同上下文 - Attach same object to different contexts in Entity Framework 6 使用多个Entity Framework上下文并行查询 - Parallelization of queries using multiple Entity Framework contexts 如何以多种形式管理实体框架上下文 - How to manage Entity Framework Contexts with multiple forms 实体框架6中多个上下文的单个事务 - Single transaction over multiple contexts in Entity Framework 6 实体框架 6:创建具有多个上下文的数据库 - Entity Framework 6: Creating database with multiple contexts 在保存新实体以解决多个上下文问题之前,在Entity Framework中创建新对象是否有意义? - Does it make sense to create new object in Entity Framework before saving it to resolve problems with multiple Contexts? 如何使用实体框架关联来自多个上下文的对象 - How to relate objects from multiple contexts using the Entity Framework 在具有多个上下文的Entity Framework上使用异步保存更改 - Using asynchronous save changes on Entity Framework with multiple contexts 使用Entity Framework 6的多个上下文,跨dbcontexts引用了多个实体 - Multiple contexts with Entity Framework 6, reference entities across dbcontexts
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM