簡體   English   中英

實體框架多對象上下文

[英]Entity Framework Multiple Object Contexts

這個問題已經以50種不同的方式被問了500次不同的時間...但是這里又是一個問題,因為我似乎找不到想要的答案:

我正在將EF4與POCO代理一起使用。

答:我有一個從ObjectContext的一個實例獲取的對象圖。 該ObjectContext被處置。

B.我有一個從ObjectContext的另一個實例中獲取的對象。 該ObjectContext也已處置。

我想使用B中的實體在A上的一堆東西上設置相關屬性...類似

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 

我猜想我需要在處理這些實體時從ObjectContext中分離這些實體,以使上述工作正常...問題是,在處理它時從我的ObjectContext中分離所有實體似乎會破壞圖形。 如果我做類似的事情:

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

圖中的所有關系似乎都不確定。

我該如何解決這個問題?

@Danny Varod是正確的。 您應該在整個工作流程中使用一個ObjectContext 此外,由於您的工作流程似乎是包含多個窗口的一項邏輯功能,因此它可能也應使用單個演示者。 然后,您將遵循推薦的方法:每個演示者使用單個上下文。 您可以多次調用SaveChanges ,這樣就不會破壞您的邏輯。

此問題的根源是眾所周知的問題,即與POCO T4模板生成的Fixup方法結合使用時,在POCO實體頂部生成的動態代理不足。 當您處理它們時,這些代理仍然保留對上下文的引用。 因此,他們認為它們仍附加在上下文中,而不能附加在另一個上下文中。 強制它們釋放對上下文的引用的唯一方法是手動分離。 同時,一旦您從上下文分離實體,該實體就會從相關的附加實體中移除,因為您不能在同一圖中混合使用附加實體和分離實體。

您調用的代碼中實際上沒有發生此問題:

itemFromA.RelatedProperty = itemFromB;

但是在Fixup方法觸發的反向操作中:

itemFromB.RelatedAs.Add(itemFromA);

我認為解決此問題的方法是:

  • 不要這樣做,而是將單個上下文用於整個工作單元-這就是假定的用法。
  • 刪除反向導航屬性,以便Fixup方法不會觸發該代碼。
  • 不要將POCO T4模板與Fixup方法一起使用,也不要修改T4模板以不生成它們。
  • 關閉這些操作的延遲加載和代理創建。 這將從您的POCO中刪除動態代理,因此,它們將與上下文無關。

要關閉代理創建和延遲加載,請使用:

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

您實際上可以嘗試編寫自定義方法來分離整個對象圖,但是正如您所說的,它被問了500次,我還沒有看到有效的解決方案-除了序列化和反序列化到新對象圖之外。

我認為您在這里有幾個不同的選擇,其中兩個是:

  1. 使上下文保持活動狀態,直到完成該過程為止,僅使用1個上下文,而不是2個。

  2. 一種。 在處置上下文1之前,請使用BinaryStreamer或ValueInjecter或AutoMapper等工具創建圖的深層克隆。

    b。 將上下文2中的更改合並到克隆的圖中。

    C。 保存后,將克隆圖的更改合並到新ObjectContext創建的圖中。


為了將來參考,該MSDN博客鏈接可以幫助您決定何時決定做什么: http : //blogs.msdn.com/b/dsimmons/archive/2008/02/17/context-lifetimes-dispose-or-reuse。 aspx

我認為您不需要解決這個問題。

我們做這樣的事情:

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

這使我們能夠提取數據,將其傳遞到另一層,讓他們做任何需要做的事情,然后將其傳遞回去,以便我們進行更新或刪除。 我們使用單獨的上下文 (每個方法 一個 (每個請求一個 )來 完成所有這些操作。

要記住的重要一點是,如果您使用的是IEnumerable,則會推遲執行它們。 意味着在您對它們進行計數或迭代之前,它們實際上不會提取信息。 因此,如果要在上下文之外使用它,則必須執行ToList(),以便對其進行迭代並創建一個列表。 然后,您可以使用該列表。

編輯由於@Nick的輸入,更新后變得更加清晰。

好的,我知道您的對象上下文已經消失了。

但是,讓我們以這種方式來看一下,Entity Framework實現了工作單元概念,在其中它跟蹤您在對象圖中進行的更改,以便它可以生成與您所做的更改相對應的SQL。 如果不依賴上下文,就無法應對變化。

如果您無法控制上下文,那么我認為您無能為力。

否則,有兩個選擇,

  1. 使對象上下文保持活動狀態以延長使用壽命,例如用戶會話登錄等。
  2. 嘗試使用自我跟蹤文本模板重新生成代理類,該模板將在斷開狀態下啟用更改跟蹤。

但是,即使進行自我跟蹤,也可能會遇到一些小問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM