Attach and update boolean or int doesn't alway

2019-06-28 00:46发布

问题:

Using Entity Framework 5, Given an object messenger that exists in the database, with bit property published, in previous versions of EF I would update it like this:

using (var c = new EFContext())
{
    Data.Messenger cm = new Messenger { MessageId = messageId };
    c.Messengers.Attach(cm);
    cm.Published = newPublishedValue;
    c.SaveChanges();
}

However, using EF5, this works if newPublishedValue is true, but if newPublishedValue is false, no changes are made to the database. Likewise, this pattern will not set integer values to 0.

What's going on here?

Replacing

c.Messengers.Attach(cm);

with

c.Entry(cm).State = System.Data.EntityState.Modified;

Fixes the issue, but if EF5 won't update properties of my new Data.Messenger that are of a default struct value, doesn't that render the Attach method a bit useless?

What am I missing here?

回答1:

It only worked in previous versions probably when you have used entities derived from EntityObject or POCOs with dynamic proxy change tracking. In that case the property setter is overridden with code that sets a Modified flag for this property when you assign a value (= call the setter) no matter what the old value was.

Using POCOs without dynamic change tracking proxies it doesn't work - for no version of EF - because the property setter is just an assignment of a data field in the entity class. Change tracking happens by snapshot change tracking which means that EF compares the values of a snapshot of the entity taken when you call Attach with the values the entity has when you call SaveChanges. If the values didn't change EF detects no changes and doesn't write an UPDATE statement for the property.

Attach is only for adding an entity to the context in Unchanged state. In your case you have to mark the property as Modified explicitly to ensure that it will be updated in the DB, no matter what the old value was:

c.Entry(cm).Property(x => x.Published).IsModified = true;