为什么实体框架会检测已修改但重置的属性的更改?

发布于 2024-12-19 05:49:17 字数 485 浏览 0 评论 0原文

如果我修改 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);

您如何处理此案?

If I modify a property of a POCO Entity, but reset it the EntityFramework still says that there are changes.

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

Entries that have been modified:

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

How do you handle this case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我一直都在从未离去 2024-12-26 05:49:17

如果您的所有属性都是虚拟的,实体框架将默认自动创建 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没有注意到你两次改变了属性并认为属性没有改变。

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

If all your properties are virtual Entity Framework will automatically create a dynamic proxy of your POCO by default. If I am not wrong change tracking is based in this case on property setters of this dynamic object, roughly like so:

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

So, there is no comparison with the original value, but only with the current value of the property. If this value gets changed the property is marked as modified, no matter if you reset it back to the original value.

(Edit and correction of the previous paragraph: The property is marked as Modified if the setter is called, no matter if the same or a changed value is assigned. Thanks to Brad Thomas and his comment below!)

You can avoid creating dynamic proxies by disabling this in the context options:

objectContext.ContextOptions.ProxyCreationEnabled = false;

Change detection will now rely on snapshot creation, which means that EF compares the original value (stored in a snapshot in the object context) with the current value when change detection is called. This does not happen anymore in property setters but inside of certain functions of Entity Framework, for example in SaveChanges. In your situation it would mean that when you call SaveChanges original value (snapshot) and current value will be the same because you did reset the change. Basically EF didn't notice that you changed the property twice and considers the property as unchanged.

Be aware that disabling proxy creation - if you do it globally, for example in the context constructor - is a potentially deep change for your application. You might have code which depends on dynamic proxies in order to work correctly and it also can affect performance heavily in various situations. Dynamic proxies exist to make change tracking fast. Snapshot based change tracking is much slower.

小清晰的声音 2024-12-26 05:49:17

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

With dynamic proxy objects, once you change a property value, the context mark it as changed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文