3

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?

Slauma
  • 175,098
  • 59
  • 401
  • 420
Rookian
  • 19,841
  • 28
  • 110
  • 180
  • Is your POCO entity a dynamic proxy (=all properties are `virtual`)? – Slauma Nov 30 '11 at 18:28
  • 2
    I assume it's because you're not actually "resetting" the value, but rather "re-setting" it. How does EF know it was changed back to the original value, unless it checked the unmodified value EVERY time a value is changed? – cwharris Nov 30 '11 at 18:34

2 Answers2

7

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.

Slauma
  • 175,098
  • 59
  • 401
  • 420
  • @Slauma You should also mention that if the property isn't virtual, it isn't tracked by the tracking proxy. That way the user can avoid sidabling the ProxyCreation for the whole context. – JotaBe May 16 '12 at 15:30
  • 1
    @Slauma Properties are marked as modified even if their value is not changed when an assignment call is made. This is readily demonstrable simply by checking EntityState before and after assigning a property it's own value. So I think your code example is inaccurate. The problem is that there is a distinct semantic difference between "Modified" ie has a modification attempt been made or "Modified" ie do the original and current values differ. Entity Framework uses the first meaning for EntityState – Bradley Thomas Jan 25 '13 at 20:33
  • 1
    @BradThomas: For some reason I never saw your comment until now. Thanks for the correction! In the meantime I'm sure I observed myself the behaviour you describe. I've edited your comment into the answer. – Slauma Jul 22 '13 at 20:02
  • This is ridiculous behavior. How come no one has put a stop to this? – N73k Oct 31 '17 at 05:19
  • "If all your properties are virtual Entity Framework will automatically create a dynamic proxy of your POCO by default" - do you have any reference to backup this statement? (I tried to look in the documentation but couldn't really find) – BornToCode Feb 07 '19 at 19:20
0

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

Yair Nevet
  • 12,725
  • 14
  • 66
  • 108