Snapshot Change Tracking with POCOs using DetectChanges() method
In the article Change tracking with POCOs, we have seen what is meant by change tracking, why should we track changes in POCO entities and ways of change tracking mechanisms with POCOs. In this article we will how to perform Snapshot Change Tracking using DetectChanges() method and its pros and cons.
We know that unlike classes inherited from EntityObject, POCO classes cannot communicate with the ObjectContext. This means that POCO entities cannot notify its changes to state manager. So, it is the responsibility of ObjectContext to synchronize the POCO data with ObjectStateEntry objects.
To synchronize the POCO data with ObjectStateEntry objects, DetectChanges() method of ObjectContext is used. When DetectChanges() method is called, ObjectContext detects the changes made to POCO entities by taking a snapshot of current state of all the entities. Note that the ObjectContext has a snap shot of entity values when the query is executed for the first time, to retrieve data from the database. The ObjectContext maintains two sets of values. The first set contains original values and the second one contains current values. We can say that the ObjectContext detects the changes made to POCO entities by comparing original and current values of all the entities and constructs the various commands to persist the changes back to the database.
By default, the SaveChanges method calls DetectChanges() method internally and we need not call it explicitly. This type of change tracking is done without creating proxies. At runtime, POCO will be in pure state without a wrapper of the proxy class. This approach is the choice of many programmers because of its simplicity. The other available mechanism - Change Tracking with proxies creates problems while serializing the objects in enterprise applications and so it is not preferred.
How Snapshot Change Tracking works
As we have seen earlier, whenever we call SaveChanges() method, synchronization happens but not immediately. Sometimes situation demands that changes to properties and relationships are detected immediately and in those cases, we should call the DetectChanges() explicitly.
The disadvantage in this mechanism is that POCO entities cannot notify its changes automatically. Unless we call DetectChanges or SaveChanges() method is called only then synchronization happens. After entities are attached to the context for the first time retrieval, they are synchronized but after any change like adding a new entity or modifying any one scalar property, they both are out of synchronization.
The DetectChanges() method iterates the entities and checks each property for changes. Iteration can be wasteful if lots of entities are to be checked.
I will demonstrate How Snapshot Change Tracking works with an example, given below. In the code given, we set the ProxyCreationEnabled property to false. And we create a POCO class as pure POCO class.
All the properties are not declared with virtual keyword and this class is pure POCO class without proxies.
Code Explanation
When we query the ObjectStateManager class, it returns the ObjectStateEntry object(s) tracked by the ObjectContext. The GetObjectStateEntry() method of ObjectStateManager class returns an ObjectStateEntry() object for a given entity. The GetObjectStateEntries() method returns a collection of ObjectStateEntry objects for a given state. The ObjectStateEntry class also exposes a number of properties such as the State property which returns the state of the entity. In the above example, we query the first customer and display the entity´s state. The entity state is displayed as Unchanged. Note that when entities are attached to the context, their state is Unchanged by default.
If we change the customer name and again display the state of the entity, surprisingly we get the state as Unchanged even though we have modified the name. But if you see the database the changes are persisted. How does this happen? In the earlier part of this article, we have discussed that the SaveChanges() method internally calls the DetectChanges() method and this method checks all the entries in the ObjectStateManager and compares all the properties of all the entities and if there is any change in the properties, that entity state will be changed to Modified. This is the reason the state is returned as Unchanged. At this point, the values of entities and the entries in the state manager are synchronized. After the synchronization process, the SaveChanges method persists the data to the database.
If we want to synchronize POCO entities and state manager entries before calling SaveChanges() method, we need to explicitly call DetectChanges() method.
We know that unlike classes inherited from EntityObject, POCO classes cannot communicate with the ObjectContext. This means that POCO entities cannot notify its changes to state manager. So, it is the responsibility of ObjectContext to synchronize the POCO data with ObjectStateEntry objects.
To synchronize the POCO data with ObjectStateEntry objects, DetectChanges() method of ObjectContext is used. When DetectChanges() method is called, ObjectContext detects the changes made to POCO entities by taking a snapshot of current state of all the entities. Note that the ObjectContext has a snap shot of entity values when the query is executed for the first time, to retrieve data from the database. The ObjectContext maintains two sets of values. The first set contains original values and the second one contains current values. We can say that the ObjectContext detects the changes made to POCO entities by comparing original and current values of all the entities and constructs the various commands to persist the changes back to the database.
By default, the SaveChanges method calls DetectChanges() method internally and we need not call it explicitly. This type of change tracking is done without creating proxies. At runtime, POCO will be in pure state without a wrapper of the proxy class. This approach is the choice of many programmers because of its simplicity. The other available mechanism - Change Tracking with proxies creates problems while serializing the objects in enterprise applications and so it is not preferred.
How Snapshot Change Tracking works
As we have seen earlier, whenever we call SaveChanges() method, synchronization happens but not immediately. Sometimes situation demands that changes to properties and relationships are detected immediately and in those cases, we should call the DetectChanges() explicitly.
The disadvantage in this mechanism is that POCO entities cannot notify its changes automatically. Unless we call DetectChanges or SaveChanges() method is called only then synchronization happens. After entities are attached to the context for the first time retrieval, they are synchronized but after any change like adding a new entity or modifying any one scalar property, they both are out of synchronization.
The DetectChanges() method iterates the entities and checks each property for changes. Iteration can be wasteful if lots of entities are to be checked.
I will demonstrate How Snapshot Change Tracking works with an example, given below. In the code given, we set the ProxyCreationEnabled property to false. And we create a POCO class as pure POCO class.
All the properties are not declared with virtual keyword and this class is pure POCO class without proxies.
Code Explanation
When we query the ObjectStateManager class, it returns the ObjectStateEntry object(s) tracked by the ObjectContext. The GetObjectStateEntry() method of ObjectStateManager class returns an ObjectStateEntry() object for a given entity. The GetObjectStateEntries() method returns a collection of ObjectStateEntry objects for a given state. The ObjectStateEntry class also exposes a number of properties such as the State property which returns the state of the entity. In the above example, we query the first customer and display the entity´s state. The entity state is displayed as Unchanged. Note that when entities are attached to the context, their state is Unchanged by default.
If we change the customer name and again display the state of the entity, surprisingly we get the state as Unchanged even though we have modified the name. But if you see the database the changes are persisted. How does this happen? In the earlier part of this article, we have discussed that the SaveChanges() method internally calls the DetectChanges() method and this method checks all the entries in the ObjectStateManager and compares all the properties of all the entities and if there is any change in the properties, that entity state will be changed to Modified. This is the reason the state is returned as Unchanged. At this point, the values of entities and the entries in the state manager are synchronized. After the synchronization process, the SaveChanges method persists the data to the database.
If we want to synchronize POCO entities and state manager entries before calling SaveChanges() method, we need to explicitly call DetectChanges() method.
More Resources
- POCO class in Entity Framework
- POCO vs Entity Objects with comparison table
- Rules to be followed while creating POCOs - 4 important rules
- How to create a POCO class, integrate with ObjectContext, executing a query with POCOs
- How to load related POCO entities - loading patterns and their differences in their usage with examples
- How to perform Lazy Loading with POCO classes
- What is Change tracking in POCOs, ways of tracking
- Change tracking with proxies, How to create proxies?
- Instantiate POCO classes using ObjectContext.CreateObject method
- Using the DetectChanges() method to Fix-up Relationship in poco entities
- Entity Framework EntityKey object
- Retrieving a single entity with GetObjectByKey method of ObjectContext using EntityKey
- How to create an EntityKey in Entity Framework
- Loading Related entities in EF
- How to change the state of an entity using ChangeObjectState method of ObjectStateManager
- ChangeState method of ObjectStateEntry class
- Update an entity in a disconnected scenario using ApplyCurrentValues method
- Using ApplyOriginalValues method
- ObjectStateEntry class
- Entity state in Entity Framework - what, how, why?
- AcceptAllChanges and SaveChanges methods in Entity Framework
Azure Q & A
Azure Platform
Grid-View
GridView CommandField example
Details-View
GridView and DetailsView Master/Detail page using SqlDataSource control
POCO
POCO overview and advantages - POCO class, Entity Framework in Enterprise Applications
Entity Framework
Query entity data model using linq to entities
Array List
Difference between arraylist and list collection
Web Services
How to create a Web service using Visual Studio.net
Form-View
FormView DataBound Event
Object Oriented Programming
Calling base class constructor in C#
Linq
Convert a sequence to a generic list using ToList()method
Project Ideas
Project ideas for students
AccountingSoftware
Accounting Software
MVC
Creating an ASP.Net MVC 3 application
.Net
Using assemblies in .net applications
ASP .Net
How to implement form validation using ASP.Net 2.0 Validation Controls
VB .Net
Constructors in Visual Basic.Net