Monday, January 27, 2014

Handling the change in Code First Entity Framework

I was not quite sure how the Code First EF manages to save only fields/data that have been changed back to the database, until came across this article Handling Record Contention in Code-First Entity Framework which mentions strategies for handling two users updating the same row in a table when using EF.

The other way is enabling the "AutoDetectChanges" property, but this will affect the performance. Have a look on EF performance and AutoDetectChanges comparison here.

This is just a summary from "Handling Record Contention in Code-First Entity Framework":

 - Add ConcurrencyCheck attribute to one or more properties in the entity class
 e.g.
Public Class Customer
  Id As String
  FirstName As String
  LastName As String
  <ConcurrencyCheck>
  <TimeStamp>
  TimeStamp As Byte()
End Class

- If you're retrieving a Customer object and moving its data to a Data Transfer Object before sending that DTO to the presentation layer, you must move the TimeStamp column into the DTO also. In an ASP.NET MVC project, you'll need to store the value in a hidden field. In an ASP.NET Web Forms project, you can put the value in a hidden control or the ViewState. In a service, you'll need to send the TimeStamp column along with the rest of the data and tell the client not to modify the value.

When the DTO comes back from the presentation layer, you'll need to re-fetch the entity object from the database and update it with the values in the DTO before calling SaveChanges. As part of that, you must move the timestamp value into the entity. This ensures that the ConcurrencyCheck column has the value from when the entity object was first retrieved.

There's a wrinkle here, though: Updating the TimeStamp column, even if you update it with the same value that it currently has in the database, causes EF to flag the entity as having been changed. That can cause SaveChanges to generate unnecessary trips to the database. So, when you update the entity object, you'll want to skip updating the TimeStamp column until you've determined that there's been some change to the entity.

You can build in your own mechanism for checking for changes or, if you're using EF 5.0, you can use EF's ChangeTracker object. When writing your own assignment statements, that just means that you check the HasChanges property on the ChangeTracker object on the DbContext object before updating the TimeStamp column on the entity, using code like this:

custExisting.FirstName = custDTO.FirstName
custExisting.LastName = custDTO.LastName
If dbc.ChangeTracker.HasChanges Then
   custExisting.TimeStamp = custDTO.TimeStamp
 
I should point out that using ChangeTracker's HasChanges property isn't free -- the property does trigger some trips to the database. If you're confident that you can live with the odd "unnecessary" update, you may want to consider skipping checking the HasChanges property on the basis that the odd extra update will be less expensive than constantly reading the HasChanges property