Concurrency with NHDAL

A very important aspect of any system is data integrity. You must have a way to verify that multi-threaded systems do not overwrite each other's data. Also it is important that partial updates never occur and that all data is written in a transaction based system where the holistic integrity of your data is preserved. The latter functionality is baked into the framework in the subdomain object. However if you have many different pieces of an application from website users to windows services to third-party integrations, you must be sure that you do not loose updates or miss updates by users overwriting incomplete data.

nHydrate handles this by using SQL Server's timestamp field. By default all tables have AllowTimestamp property set to true. The generated SQL scripts and associated entity code have this field incorporated into them. When data is loaded from store the current timestamp is loaded as well. When a record is updated or deleted the database row's timestamp must match the one previously loaded. If they do not match, an exception is thrown. When calling the persist code in the generated API you must catch this error and handle it appropriately. In a website, this might be telling the user that his changes did not make it or in a Windows service logging the fact. In any case, when a persist fails the whole transaction fails. So whatever actions were being performed including all the additions, updates, and deletes will be rolled back and no changes will be made.

//Create context 1
using (var context1 = new NorthwindEntities())
{
	//Create context 2
	using (var context2 = new NorthwindEntities())
	{
		//Select the same customer from both contexts into memory at same time
		var customer1 = context1.Customer.FirstOrDefault();
		var customer2 = context2.Customer.FirstOrDefault();

		//Change customer 1 and save
		customer1.Name = "Fred";
		context1.SaveChanges();

		//Change customer 2 and save
		customer2.Name = "Sally";
		context2.SaveChanges(); //ERROR
	}
}

In the code above, I have loaded the same Customer from two contexts. I did to create two different transactions on save. Remember that a context is like an in-memory database. It is completely separate from all other contexts that might be loaded. I change the value of the Name property and persist the customer1 object. This object is persisted back to the database with no issues. The Timestamp of the column in the database changes automatically when the update has occurred. There is nothing more programmatically I need to do. Now I change the Name value of the customer2 object. When I call its SaveChanges method, a database call is made and an exception is thrown. The Timestamp in memory for customer2 does not match the Timestamp in the database, therefore the row will not be persisted.

Last edited May 8, 2012 at 2:06 AM by codetools, version 3

Comments

No comments yet.