2016-11-05 83 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); 
} 

当我做这两种方法中的一个,我的代码运行速度流畅。