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

C# 为什么实体框架检测到已修改但已重置的属性的更改?,c#,entity-framework,entity-framework-4,change-tracking,objectstatemanager,C#,Entity Framework,Entity Framework 4,Change Tracking,Objectstatemanager,如果我修改POCO实体的属性,但将其重置,EntityFramework仍会说有更改 Property "Name": Value "Test" (original value) -> Value "Test123" (value changed by UI) -> Value "Test" (value changed by UI to original value) 已修改的条目: var objectStateEnt

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

您如何处理这种情况?

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


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

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

您的POCO实体是动态代理吗(=所有属性都是虚拟的?)?我想这是因为您实际上并没有“重置”该值,而是“重新设置”它。EF如何知道它已更改回原始值,除非每次更改值时都检查未修改的值?@Slauma您还应该提到,如果属性不是虚拟的,则跟踪代理不会跟踪它。这样,用户就可以避免为整个上下文创建代理。@Slauma属性被标记为已修改,即使在进行赋值调用时它们的值没有更改。这一点很容易证明,只需在指定属性及其自身值之前和之后检查EntityState即可。所以我认为你的代码示例是不准确的。问题在于,“修改”即是否尝试修改或“修改”即原始值和当前值是否不同之间存在明显的语义差异。实体框架使用EntityState@BradThomas当前位置由于某种原因,我直到现在才看到你的评论。谢谢你的更正!与此同时,我确信我观察到了你描述的行为。我把你的评论编辑成了答案。这是荒谬的行为。为什么没有人阻止这一点?“如果您的所有属性都是虚拟实体,那么默认情况下,框架将自动为您的POCO创建一个动态代理”-您是否有任何关于备份此语句的参考?(我试图查看文档,但实际上找不到)