EF5: Rejecting changes to a single property

You have probably heard about the high-profile features of EF5—things like enums, spatial types, TVF support, and the perf improvements. But there is one little feature you may not have heard about—the ability to reject changes to an individual property. That is, to reset the IsModified flag of a property such that the value of that property will not be sent to the database.

I previously blogged on the EF Team blog about working with properties in DbContext. That post described how to check whether or not a property is marked as modified, and how to mark a property as modified. In that post I stated, “It is not currently possible to reset an individual property to be not modified after it has been marked as modified. This is something we plan to support in a future release.” Well, EF5 is that future release!

What is a modified property?

A property is marked as modified if DetectChanges determines that its current value is different from the value it had when the entity was queried or attached. Also, if you set the state of an entity to Modified, then all the entity’s properties are marked as modified.

Being marked as modified is important because only values of properties that are marked as modified will be sent to the database when SaveChanges is called.

Checking for modified properties

Consider a User entity like so:

public class User
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public byte[] ProfilePicture { get; set; }
    public DateTime? MemberSince { get; set; }

You can check if a property of an entity is marked as modified using code like this:

bool emailIsModified = context.Entry(user)
    .Property(u => u.Email)

Marking properties as modified

You can also mark a property as modified using code like this:

    .Property(u => u.Email)
    .IsModified = true;

This forces the property value to be sent to the database even if its current value is the same as its original value. This can be useful in an n-tier application such as a web app where original values are not known because the entity has traveled to and from the client and then re-attached to a new context.

Most commonly this is done at the entity level (instead of the property level) by changing the state the entity to Modified, thereby marking all properties as modified.

Rejecting changes to modified properties

When using EF5 on .NET 4.5 you can now mark a modified property as not modified again using code like this:

    .Property(u => u.Email)
    .IsModified = false;

(You need to be running EF5 on .NET 4.5 for this to work because it makes use of changes to the core EF libraries in the .NET Framework.)

When you tell EF that a property is no longer modified the context will do two things:

  • It will reset the current value to the original value stored when the entity was queried or attached. (If the original value is not known then this will have no observable effect.)
  • It will reset the modified flag.

Because the modified flag is reset it means that when SaveChanges is called the value for the property will not be sent to the database.

An example

One place where this behavior can be useful is when you want to mark all the properties of an entity as modified but then selectively choose some that you don’t want sent to the database.

For example, imagine you want to let a user modify his or her contact information and for simplicity you don’t want to keep track of exactly which properties the user edited. But you know that there are some properties that cannot be edited. For example, maybe the MemberSince property will never change and the ProfilePicture property is changed through a different UI with a different Update method. Saving the changes to the user entity without saving MemberSince or ProfilePicture could then be done like so:

public void Update(User user)
    var entry = _context.Entry(user);

    // Attach user entity and set all properties as modified
    entry.State = EntityState.Modified;

    // Reset modified state on just two properties
    entry.Property(u => u.ProfilePicture).IsModified = false;
    entry.Property(u => u.MemberSince).IsModified = false;

    // Values for ProfilePicture and MemberSince will not be
    // included in UPDATE statement sent to database

In this case ProfilePicture might be quite large so avoiding sending data (that hasn’t changed) to the database can be quite advantageous.

So there you have it. A small feature of EF5 (on .NET 4.5), but hopefully a useful one.

4 comments on “EF5: Rejecting changes to a single property

  1. Hi Arthur!
    I found your blog very usefull and i like the way you describe EF, knowing inner EF mechanism gives much more information than short overview or simple (mostly for idiots) guides how to start or continue with new feature. Thank you!

    Regarding current post: Looks like you have discussion about this feature within team and endup with example that can be described as “hack”, from my point of view. ;) May be you can remember other cases where described feature can be vitaly usefull?

    I don’t argue that this feature may be usefull =)

  2. @violettape Which part specifically seems like a hack? In general, this feature is useful when you are using EF for change tracking but wish to undo some change that was made. For example, maybe in a WPF or Windows Forms app a user has edited some values and EF is tracking those changes. But then the user undoes those changes so now the app wants to mark them as not modified anymore so that new values will not be sent to the database. Previously this was not possible; now it is.

    • I see, now it’s look reasonable for data transfer optimization.

      Exact part, that looks like a hack (to be honest it’s “logic hack”), is that I can undo changes on thouse fields that shouldn’t be changed by app logic. I believe that there are should be another algorithms that control (prohibit) described behaviour. =)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s