Wed 04 April 2018
Last time we introduced how to query database from conceptual models. It includes LINQ to Entities and Entity SQL. With
IQueryable object, the sql script will be built and executed automatically within the method
.ToList(). After the data is loaded in our program, we'll operate against them and save changes back to the database. Today we'll talk about how Entity Framework manage the changes in our program.
When the query executes through
ObjectContext and is materialized into objects, Entity Framework takes a snapshot of an entity’s values. The context stores two set of values of the entity. One of them is the original values of the object and it remains static. The other one will be a realtime values that being modified in the program. The object that saved the two set of values is named
ObjectStateEntry. Every object returned from database will have an instance of
ObjectStateEntry as a shadow.
ObjectStateEntry has a property
State to reflect the state of the entity(
Deleted). As the user modifies the objects, the
ObjectContext updates the current values of the related
ObjectStateEntry as well as its
The entity object itself also has an
EntityState property, which it inherits from
EntityObject. As long as the object is being managed by the context, its
EntityState will always match the
State of the
ObjectStateEntry. If the object is not being managed by the context, there is no
ObjectStateEntry and the entity’s
After finish modifying conceptual objects that loaded from context, we could easily get these changes applied to database by call the method of
SaveChanges against the context. And by doing that all the SQL scripts will be automatically generated and executed.
When the context was notified of a property change, not only did it modify the current value in the
ObjectStateEntry, but it also set another tracking value that indicates that the property was changed. During
SaveChanges, the context then looks for those tracking values to determine which fields were changed.
var customer = context.Customers.FirstOrDefault.Where(c => c.Name == "Jason"); customer.IsObsolete = true; context.SaveChanges();
WIth SQL Profiler, we'll get the executing sql:
exec sp_executesql N'update [dbo].[Customers] set [IsObsolete] = @0 where ([Name] = @1)' ,N'@0 bit,@1 nvarchar(50)' ,@0=1, @1='Jason'
No tracking query, as the name suggest, means the objects that returned by the query would not be managed by the context. Though it relates to what is called
MergeOption for querying, which controls how to deal with result with existing cached objects in context (queried in the same transaction).
When querying with
NoTracking option, it does not only means the
SaveChanges will not save any changes on those objects, but also means all the
ObjectStateEntry objects creation will be skipped by Entity Framework. Based on these two features,
NoTracking is often used for readonly data querying and it improves the performance significantly for large volume of data.