2016-11-05 42 views
1

我有以下的(僞)代碼......實際的代碼要複雜得多,但這是根本問題的要點:如何防止實體框架4.x中的孤立對象?

string customXML = GoFetchCustomXML(); 
    using (MyContext ctx = new MyContext(...)) 
    { 
     SomeTable tbl = CreateEntryInTable(customXML); 

     ctx.SomeTables.AddObject(tbl); 

     ctx.SaveChanges(); 
    } 


... 

public SomeTable CreateEntryInTable(string customXML) 
{ 
    XDocument doc = XDocument.Parse(customXML); 
    SomeTable ret = new SomeTable(); 

    foreach (XElement descendant in doc.Descendants("ChildObject").ToList()) 
    { 
     ChildTable ct = new ChildTable(); 

     // Set some initial items about ct based on 
     // customer configurations. It sets our StatusCodeID to "NEW". 
     initializeCT(ct, SomeGlobalCustomerObject); 

     if (ValidateChildObject(descendant, ct)) 
     { 
      // Set final ct properties here. We move the 
      // StatusCodeID to "Valid" among many other things. 

      // Before we go on, set CreateDate 
      ct.CreateDate = DateTime.Now; 

      ret.ChildTables.AddObject(ct); 
     } else { 
      // Do nothing. We've changed our mind about needing 
      // a ChildTable object. 
     } 
    } 

    return ret; 
} 

我已經花掉了今天8小時追下來這很奇怪的問題。我遇到了一個謎題:The element at index 0 in the collection of objects to refresh is in the added state. Objects in this state cannot be refreshed.

當我運行代碼時,在「後代」的第三個循環中,它沒有通過驗證,所以它永遠不會被添加到ChildTables中。這應該是有效的,對嗎? (如果沒有,請讓我知道!)

然而,正如我深深的發現 - 它已被添加到上下文莫名其妙。它的身份欄實際上是「0」。當程序進入「SaveChanges()」時,它會崩潰,因爲記錄上的日期(創建日期)是00/00/0001,這在數據庫中無效。當我把profiler放在連接上時,我看到它的StatusCodeID == NEW ...但是這個記錄從來沒有完成過,也沒有添加到CTX對象或ChildTables中。

更糟糕的是,現在這是在這個狀態,上下文是烤麪包。我無法找到該記錄來殺死它,並且我無法保存任何內容,因爲它是上下文中某處的孤立記錄。

如果我跳過「無效」對象或重寫我的代碼,直到我們確定它將被真正需要並添加到ChildTables時才創建對象,那麼它就可以工作。但是我上面所做的應該是合法的,不是嗎?如果沒有,有人可以解釋爲什麼嗎?

+0

我猜'ct'是附加到'initializeCT()'中的上下文。 –

+0

不是。它從未附加到代碼中的上下文中。我已經證實了這一點。 – Jerry

回答

0

我找到了答案,或者至少是非常有意義的解決方法。

1)除非我確信我需要添加它們,否則不要創建該對象。我可以重寫ValidateChildObject以使Descendant和SomeCustomerObject確定它是否有效,並且只有在規則通過時才創建並初始化CT。 2)然而,有些情況下,這在目前的設計中是不可行的,因爲它會減慢速度 - 無論我需要做什麼來驗證某些設置,我都必須重新設置這些設置initializeCT中的值。在這種情況下,作爲「ELSE」上述條款中,我需要做的:

... 
} 
else 
{ 
    // Remove it from the ChildTables anyway, just in case 
    // it was magically added. If it was not added, this does not fail. 
    ctx.ChildTables.DeleteObject(ct); 
} 

當我做這兩種方法中的一個,我的代碼運行速度流暢。