3

如果我修改了 POCO 实体的属性,但将其重置,EntityFramework 仍然会说有更改。

Property "Name": Value "Test" (original value) 
              -> Value "Test123" (value changed by UI) 
              -> Value "Test" (value changed by UI to original value)

已修改的条目:

var objectStateEntries = 
    _db.ObjectStateManager.GetObjectStateEntries(
        EntityState.Added | 
        EntityState.Deleted | 
        EntityState.Modified);

你如何处理这个案子?

4

2 回答 2

7

如果您的所有属性都是virtual实体框架,默认情况下会自动创建您的 POCO 的动态代理。如果我没记错的话,在这种情况下,更改跟踪基于此动态对象的属性设置器,大致如下:

private string _name;
public string Name
{
    // ...
    set
    {
        // if (_name != value) such a check probably does not happen
        {
            _name = value;
            MarkPropertyAsModified(...);
        }
    }
}

因此,没有与原始值进行比较,而只是与属性的当前值进行比较。如果此值发生更改,则无论您是否将其重置为原始值,该属性都会被标记为已修改。

上一段的编辑和更正:如果调用了 setter,则无论分配相同还是更改的值,该属性都标记为已修改。感谢 Brad Thomas 和他在下面的评论!)

您可以通过在上下文选项中禁用它来避免创建动态代理:

objectContext.ContextOptions.ProxyCreationEnabled = false;

更改检测现在将依赖于快照创建,这意味着 EF 在调用更改检测时将原始值(存储在对象上下文中的快照中)与当前值进行比较。这不再发生在属性设置器中,而是在实体框架的某些函数内部,例如在SaveChanges. 在您的情况下,这意味着当您调用SaveChanges原始值(快照)时,当前值将是相同的,因为您确实重置了更改。基本上 EF 没有注意到您两次更改了该属性并认为该属性未更改。

请注意,禁用代理创建 - 如果您在全局范围内进行,例如在上下文构造函数中 - 对您的应用程序来说可能是一个深刻的变化。您的代码可能依赖于动态代理才能正常工作,并且在各种情况下也会严重影响性能。存在动态代理以快速跟踪更改。基于快照的更改跟踪要慢得多。

于 2011-11-30T18:53:18.260 回答
0

使用动态代理对象,一旦您更改了属性值,上下文会将其标记为已更改。

于 2012-05-01T11:39:41.667 回答