50

Given the following code, how does EF/DbContext knows about the change made to the customer object:

class Program
{
    static void Main()
    {
        using(var shopContext = new ShopContext())
        {
            var customer = shopContext.Customers.Find(7);

            customer.City = "Marion";

            customer.State = "Indiana";

            shopContext.SaveChanges();
        }
    }
}

public class ShopContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
}

public class Customer
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

Thank you

Yair Nevet
  • 12,725
  • 14
  • 66
  • 108
  • 4
    For new reaaders, this blog post might be helpful: http://blog.oneunicorn.com/2012/03/10/secrets-of-detectchanges-part-1-what-does-detectchanges-do/ – Karsten Jun 18 '13 at 11:25

1 Answers1

70

When you load the entity from the context it keeps an additional data structure - let's call it entry. The entry contains two set of values - original values and current values. When you execute the SaveChanges operation EF goes through your customer entities and updates current values in the entry so that they match with the real state of your entity - this operation is called detecting changes. During SQL command generation EF will compare current and original values and build an SQL update statement to modify changed values in the database. This operation is called snapshot change tracking - EF keeps a snap shot in the entry.

There is an alternative called dynamic change tracking which will modify the current value in the entry at the same time you assign the value to your entity's property. Dynamic change tracking has specific requirements (like all of your properties in the entity must be virtual) because it must wrap your class to a dynamic proxy at runtime. This used to be the preferred way but due to some performance issues in complex scenarios, snapshot change tracking is currently supposed to be used as default.

Jess
  • 23,901
  • 21
  • 124
  • 145
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • hi, how does the context knows about the customer object? How does it connected/linked? – Yair Nevet Apr 30 '12 at 09:53
  • Context knows about it because you retrieved the customer object through the same context instance by calling `Customers.Find` – Ladislav Mrnka Apr 30 '12 at 10:11
  • @Ladislav: Does your last sentence mean that proxy change tracking is worse in performance than snapshot change tracking in some situations? Do you know examples? I always thought that proxy change tracking is much faster in every situation... – Slauma Apr 30 '12 at 13:37
  • 2
    @Slauma: Check [this article](http://blog.oneunicorn.com/2011/12/05/should-you-use-entity-framework-change-tracking-proxies/). Arthur is member of EF dev. team and if you check every code first example provided by ADO.NET team or DbContext generator template you will see that change tracking proxies are not default behavior anymore. It appears that performance problems with snapshot change tracking are easier to identify and solve by switching to change tracking proxies. – Ladislav Mrnka May 01 '12 at 19:06
  • @Ladislav: Thanks for the reference! I had to edit an old answer that was praising change tracking proxies too much. – Slauma May 02 '12 at 13:06
  • I don't know if this is entirely accurate. I'm seeing a situation where if you pull down an entity from a DbContext, set the value of a property to the same value it already has, and then check _dbContext.Entry(property).State, its state will then be "Modified". It's as if, even though the value has not changed, the fact that its setter was utilized causes it to be considered "Modified" as opposed to "Unchanged". – boylec1986 Jan 18 '18 at 17:39