2012-11-07 67 views
2

我在更新ASP.NET應用程序中斷開連接的POCO模型時遇到問題。如何處理斷開的對象圖中的重複項?

比方說我們有以下模型:

  1. 用戶
  2. 訂單

用戶可以負責0以上的地區,訂單屬於區並且用戶可以是訂單的所有者。

當用戶登錄用戶並加載相關區域時。稍後用戶加載訂單,並將自己設置爲訂單的所有者。用戶(和相關區域)和訂單(以及相關區域)在兩個不同的調用中使用兩個不同的dbcontext進行加載。在用戶將自己分配給它時保存訂單。我得到一個異常,說acceptchanges不能繼續,因爲對象的鍵值與另一個對象衝突。

這並不奇怪,因爲同一地區可以出現在用戶負責的地區列表和訂單上。

我已經搜查高和低的解決這個問題,但我已經找到了答案似乎是兩種:

  1. 不要加載的對象之一的相關實體在我的情況那將是用戶的區域。
  2. 請勿通過使用對象將用戶分配到訂單,只需在訂單對象上設置外鍵標識。
  3. 使用nHibernate,因爲它顯然處理它。

我試過1並且可以工作,但是我覺得這是錯誤的,因爲那麼我必須先加載沒有區域的用戶,然後再將它與訂單關聯起來,或者做一個淺層克隆。對於這個簡單的案例來說,這很好,但問題是在我的案例中,區域可能會在圖表中出現多次。此外它似乎毫無意義,因爲我有對象,所以爲什麼不讓我連接它們並更新圖形。我需要訂單的整個圖表的原因是我需要向用戶顯示所有信息。所以,因爲我得到了所有的對象,爲什麼我需要重新加載或淺層克隆它才能使其工作?

我試過使用STE,但我遇到了同樣的問題,因爲我無法將對象附加到由另一個上下文加載的圖上。所以我回到原點1.

我會認爲這是除教程代碼之外的其他任何問題的常見問題。然而,我似乎無法找到任何好的解決方案。這讓我想,要麼我不在任何情況下理解使用POCOs/EF或我吮吸使用谷歌找到這個問題的答案。

我已經從Julia Lerman的O'Reilly購買了兩本「編程實體框架」書籍,但似乎無法找到任何解決我的問題的書籍。

有沒有人可以闡明如何處理圖形,其中一些對象可能會重複,而不一定從相同的上下文中加載。

+0

歡迎的StackOverflow!這是一個很好的問題。雖然我不知道答案,但我可以告訴你它會得到一些關注。 –

回答

0

之所以EF不允許有兩個實體連接到上下文相同的密鑰的存在是EF無法知道哪一個是「有效的」。例如:在對象圖中可以有兩個District對象,都使用Id = 1鍵,但這兩個對象具有不同的Name屬性值。哪一個表示必須保存到數據庫的數據?

現在,你可以說如果兩個對象都沒有改變就沒關係,你只需要將它們附加到狀態爲Unchanged的上下文中,也許可以建立與另一個實體的關係。在這種特殊情況下,重複可能不成問題。但是我認爲,處理所有情況和對象可能需要判斷重複對象是否導致歧義的不同狀態是非常複雜的。

無論如何,EF實現對象引用標識和密鑰屬性值和只是不允許有一個以上的實體與附接到上下文給定的密鑰之間的嚴格的同一性的映射。

我不認爲有這種問題的一般解決方案。我只能除了在你的問題的解決方案增加了更多思路:

  • 附上User爲您加載順序上下文:

    context.Users.Attach(user); // attaches user AND user.Districts 
    var order = context.Orders.Include("Districts") 
        .Single(o => o.Id == someOrderId); 
    // because the user's Districts are attached, no District with the same key 
    // will be loaded again, EF will use the already attached Districts to 
    // populate the order.Districts collection, thus avoiding duplicate Districts 
    order.Owner = user; 
    context.SaveChanges(); 
    // it should work without exception 
    
  • 連接只有實體你爲了執行特殊的更新需要上下文:

    using (var context = new MyContext()) 
    { 
        var order = new Order { Id = order.Id }; 
        context.Orders.Attach(order); 
        var user = new User { Id = user.Id }; 
        context.Users.Attach(user); 
    
        order.Owner = user; 
    
        context.SaveChanges(); 
    } 
    

    這將足以更新Owner關係。您不需要此過程的整個對象圖,只需要爲該關係必須創建的實體創建正確的主鍵值。當然,如果你有更多的變化來保存或不知道究竟是什麼可能發生了變化,那麼這並不容易。

  • 根本不要將對象圖添加到上下文中。而是從數據庫加載表示當前存儲在數據庫中的對象圖的新實體。然後使用分離的對象圖更新加載的圖並保存應用於加載(=附加)圖的更改。該過程的一個例子如here所示。它是安全的和非常普遍的模式(但不是通用的),但對於複雜的對象圖可能非常複雜。

  • 遍歷對象圖並更換由唯一的一個重複的對象,例如只是第一個與類型和密鑰你已經找到。您可以創建一個您要查找的獨特對象的字典來替換重複對象。一個例子是here

+0

Crud,這正是我所害怕的,在積極的一面,我沒有誤解任何東西。感謝您確認我的懷疑。 :) –