简体   繁体   English

如何防止Entity Framework 4.x中的孤立对象?

[英]How do I prevent orphaned objects in Entity Framework 4.x?

I have the following (pseudo-)code... the actual code is much more complex, but this is the gist of the root issue: 我有以下(伪)代码......实际代码要复杂得多,但这是根本问题的要点:

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

I've spent over 8 hours today chasing down a very strange issue with this. 今天我花了8个多小时来处理一个非常奇怪的问题。 I was getting a mystery error: The element at index 0 in the collection of objects to refresh is in the added state. Objects in this state cannot be refreshed. 我得到一个神秘的错误: The element at index 0 in the collection of objects to refresh is in the added state. Objects in this state cannot be refreshed. The element at index 0 in the collection of objects to refresh is in the added state. Objects in this state cannot be refreshed.

When I run the code, on the third loop of "descendant" it doesn't pass validation, so it is never added to ChildTables. 当我运行代码时,在“后代”的第三个循环上它没有通过验证,所以它永远不会添加到ChildTables。 This should be valid, right? 这应该是有效的,对吗? (If not, please let me know!) (如果没有,请告诉我!)

HOWEVER -- as I've sorely discovered -- it has been added to the context somehow. 然而 - 正如我已经发现的那样 - 它已被某种方式添加到上下文中。 It's identity column is in fact "0". 它的标识列实际上是“0”。 When the program gets to "SaveChanges()", it crashes because the date on the record (create date) is 00/00/0001, which is not valid at the database. 当程序进入“SaveChanges()”时,它会崩溃,因为记录上的日期(创建日期)是00/00/0001,这在数据库中无效。 When I put profiler on the connection, I see that its StatusCodeID == NEW... but this record was never completed and never added to the CTX object or to ChildTables. 当我在连接上放置探查器时,我看到它的StatusCodeID == NEW ...但是这条记录从未完成,并且从未添加到CTX对象或ChildTables。

What's worse, is that now that this is in this state, the context is toast. 更糟糕的是,现在这是在这种状态,上下文是敬酒。 I can't find this record to kill it, and I can't save anything because it is an orphaned record somewhere in the context. 我找不到这条记录来杀死它,我无法保存任何东西,因为它是在上下文中某处的孤立记录。

If I skip the "invalid" object or rewrite my code such that the object is not created until we are CERTAIN that it will really be needed and added to ChildTables, then it works. 如果我跳过“无效”对象或重写我的代码,使得在我们确实需要将对象真正需要并添加到ChildTables之后才创建对象,那么它可以工作。 But what I've done above should be legal, shouldn't it? 但我上面所做的应该是合法的,不是吗? If not, can someone explain why? 如果没有,有人可以解释原因吗?

I found the answer, or at least a very significant work-around. 我找到了答案,或者至少是一个非常重要的解决方案。

1) Don't create the object unless I'm fairly sure that I'm going to need to add them. 1)除非我非常确定我需要添加它们,否则不要创建对象。 I could rework ValidateChildObject to take the Descendant and SomeCustomerObject to determine if it was valid and only create and initializeCT if the rules pass. 我可以重新修改ValidateChildObject以使Descendant和SomeCustomerObject确定它是否有效,并且只有在规则通过时才创建和初始化。

2) HOWEVER, there are cases when this isn't feasible in the current design as it would slow things down -- whatever I have to do to validate some settings, I would have to do again in order to set those values in initializeCT. 2)然而,有些情况在当前设计中这是不可行的,因为它会减慢速度 - 无论我需要做什么来验证某些设置,我都必须再做一次,以便在initializeCT中设置这些值。 In those cases, as in the "ELSE" clause above, I need to do: 在这些情况下,如上面的“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);
}

When I do one of these two approaches, my code runs smoothly. 当我执行这两种方法之一时,我的代码运行顺利。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM