2012-05-28 16 views
3

我正在使用實體框架和DbContext API來構建我的應用程序,但我無法處理具有多對多關係的對象。簡化保存法可能看起來像這樣使用DbContext API添加和刪除多對多API

public void MyObj_Save(MyObj myobj) 
{ 
    DbContext.Entry(myobj).State = EntityState.Added; 
    DbContext.SaveChanges(); 
} 

此代碼工作正常,但如果MyObj中包含了許多一對多的關係,這是不會被保存。我使用舊的POCO API,我需要附上相關對象上下文知道,但我不能找到一種方法,用的DbContext API正確地做到這一點 - 以下

public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList) 
{ 
    foreach (OtherObj otherObj in otherObjList) 
    { 
    DbContext.OtherObj.Attach(otherObj); 
    myobj.OtherObj.Add(otherObj); 
    } 

    DbContext.Entry(myobj).State = EntityState.Added; 
    DbContext.SaveChanges(); 
} 

一個簡單的例子我沒有得到任何錯誤,但關係不會被保存。該怎麼辦?

+0

它應該工作。是否保存了myobj?但連接表中沒有新行? – Slauma

+0

通過將實體附加到上下文中,您不確定要實現什麼目標。如果你附加,那麼它「向ObjectContext添加一個對象,並將該對象設置爲Unchanged狀態。在Unchanged狀態下,實體框架將實體鍵值視爲final。如果多於一個特定類型的實體具有相同的鍵值,實體框架將拋出​​一個異常。爲避免發生異常,請使用AddObject方法附加分離的對象,然後相應地更改狀態。請參閱MSDN [文章](http://msdn.microsoft.com/en-us/library/bb896271.aspx)。 –

+0

@EmmieGabrielleLewis:他想創建** new **對象'myobj'和**現有**對象'otherObjList'的列表之間的關係。使用'Attach'對此是正確的。 – Slauma

回答

3

我引用您的(重要!)評論:我送的方法

的對象連接和EntityState是 不變。我的DbContext的配置是,我有禁用 AutoDetectChangesEnabled ...

所以,你的代碼應該是這樣的:

DbContext.Configuration.AutoDetectChangesEnabled = false; 

DbContext.Entry(myobj).State = EntityState.Unchanged; 
foreach (OtherObj otherObj in otherObjList) 
    DbContext.Entry(otherObj).State = EntityState.Unchanged; 

// entering MyObj_Save method here 
foreach (OtherObj otherObj in otherObjList) 
{ 
    //DbContext.OtherObj.Attach(otherObj); // does not have an effect 
    myobj.OtherObj.Add(otherObj); 
} 

DbContext.Entry(myobj).State = EntityState.Added; 
DbContext.SaveChanges(); 

這確實不起作用,因爲沒有按EF請注意,您已更改myobjmyobj.OtherObj.Add(otherObj);行中的OtherObj列表之間的關係,因爲您已禁用自動更改檢測。所以,沒有條目會寫入連接表。只有myobj本身將被保存。

您不能在實體上設置任何狀態,以將狀態管理器置於關係被保存的狀態,因爲它不是一個實體狀態,在這裏它很重要,而是關係狀態。這些是對象狀態管理器中的單獨條目,它們是通過更改檢測創建和維護的。

我看到三個解決方案:

  • DbContext.Configuration.AutoDetectChangesEnabled = true;

  • 呼叫DetectChanges手動:

    //... 
    DbContext.Entry(myobj).State = EntityState.Added; 
    DbContext.ChangeTracker.DetectChanges(); 
    DbContext.SaveChanges(); 
    
  • 拆離新myobj從你設置成Added狀態之前的上下文(這對我來說感覺很不好):

    // entering MyObj_Save method here 
    DbContext.Entry(myobj).State = EntityState.Detached; 
    foreach (OtherObj otherObj in otherObjList) 
    //... 
    

也許是可能的 - 通過將IObjectContextAdapter獲取到ObjectContext - 手動修改對象狀態管理的關係項,但我不知道怎麼辦。

在我看來,這個手動操作實體(和關係)狀態的過程並不是你應該使用EF的方式。 AutoDetectChangesEnabled已被引入使EF的工作更加簡單和安全,並且唯一推薦的禁用它的情況是高性能要求(例如對於批量插入)。如果您在不需要自動更改檢測功能時遇到難以檢測到的問題,並且需要EF內部工作的高級知識才能修復這些錯誤。

+0

來吧,我的所有尊重 - 我知道爲什麼它不起作用,但我找不到一個不會影響架構決策或可能導致其他缺陷的解決方案。確切地說要保存哪些對象或不保存。我不是在尋找簡單的解決方案,並且自動檢測更改可以輕鬆地在大型應用程序中提供問題。無論如何 - 這種幻想讓我們彼此之間更加接近理解,所以讓我們在這裏結束,而且我也找到了解決方案,我將在下面發佈答案。 – keysersoze

+0

@keysersoze:我的答案中包含了您自己的答案(至少提到過)作爲選項。但是:我真的不喜歡它! (但很好知道它是如何工作:)) – Slauma

2
public void MyObj_Save(MyObj myobj, List<OtherObj> otherObjList) 
{ 
    DbContext.Entry(myobj).State = EntityState.Added; 

    foreach (OtherObj otherObj in otherObjList) 
    { 
     (((System.Data.Entity.Infrastructure.IObjectContextAdapter)DbContext) 
      .ObjectContext) 
      .ObjectStateManager 
      .ChangeRelationshipState(myobj, otherObj, 
       q => q.OtherObjs, EntityState.Added); 
    } 

    DbContext.SaveChanges(); 
} 

再一次,它是一個簡化而不是真實的生活實例!

+0

我重新格式化了一下代碼(換行符),因爲它值得輕鬆閱讀! – Slauma