【问题标题】:How do I prevent orphaned objects in Entity Framework 4.x?如何防止 Entity Framework 4.x 中的孤立对象?
【发布时间】:2017-03-23 01:45:40
【问题描述】:

我有以下(伪)代码...实际代码要复杂得多,但这是根本问题的要点:

    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,这在数据库中是无效的。当我将探查器放在连接上时,我看到它的 StatusCodeID == NEW... 但这条记录从未完成,也从未添加到 CTX 对象或 ChildTables 中。

更糟糕的是,现在它处于这种状态,上下文是 toast。我找不到这条记录来杀死它,也无法保存任何内容,因为它是上下文中某处的孤立记录。

如果我跳过“无效”对象或重写我的代码,以便在我们确定确实需要它并将其添加到 ChildTables 之前不会创建该对象,那么它就可以工作。但是我上面所做的应该是合法的,不是吗?如果不是,有人可以解释原因吗?

【问题讨论】:

  • 我猜ct 附加到initializeCT() 的上下文中。
  • 没有。它永远不会附加到代码中的上下文。我已经验证过了。

标签: c# entity-framework-4


【解决方案1】:

我找到了答案,或者至少找到了一个非常重要的解决方法。

1) 不要创建对象,除非我相当确定我需要添加它们。我可以重新设计 ValidateChildObject 以获取 Descendant 和 SomeCustomerObject 来确定它是否有效,并且只有在规则通过时才创建和初始化CT。

2) 但是,在某些情况下,这在当前设计中是不可行的,因为它会减慢速度——无论我必须做什么来验证某些设置,我都必须重新设置这些值在初始化CT中。在这些情况下,就像上面的“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);
}

当我使用这两种方法之一时,我的代码运行顺利。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多