In the first part in the series (here), I showed how easy it was to convert Nerd Dinner to use Dapper. In a subsequent post (here), I improved upon the solution and showed the power of Dapper. Now in this post I will continue improving the solution and show how we can manage the state of objects.
Entity Framework is an incredibly powerful ORM; one of its best features is that it tracks the changes of objects and can say if it is new, modified, deleted or unchanged. This means when queries are sent to the database they can be optimised depending on the state of the object.
Sadly Dapper has no concept of change tracking built in, which means that we have to track it ourselves. This is not just Dapper - most micro ORM's can't do this either and if you use ADO.NET you have to manage the state yourself as well. Up until now, I implemented a simple change tracker system whereby if the "ID" of the object is zero then it must be new, otherwise it was modified. This works fine in simple situations, however if you have an object with a collection how can you tell if an item in the collection is modified or unchanged when saving? Using the simple method you cannot, and you may end up making an unnecessary call to the database by updating objects that have not changed. This is clearly not the most efficient way of handling updates. The following is what I change in the Dapper Dinner solution to make object management simpler:
The first step is to create a new `enum` called "ObjectState" that has the various states an object can be: unchanged, modified, added and deleted. The next step is to create a simple interface that all business objects inherit from, that contains a property for the "ObjectState" `enum`.
As the repository layer handles all the calls to and from the database, the majority of the code changes will take place here. The first change is to add two new methods that return a new Dinner and a new RSVP; both these new objects returned will have their state set to "new". (The new repository interface can be seen below.) Now we need to handle how objects are added and updated. This is a simple change, in the `InsertOrUpdate` methods all that needs to change is to check if the object state is set to "new" or "modified", anything else is just ignored. This now prevents any unnecessary changes being sent to the database.
Now that the repository has been modified we now need to update the controllers to reflect these changes. Again this is a relatively simple change. Where new objects are created, instead of calling the constructor method of the object we now call the "new" methods on the repository and where we edit an object we can set the object state property to "changed".
As you can see with a few more minor changes to the code base we now have full object change tracking. This is a complete solution that has efficient queries and is quick. A bit more work was required than if I used Entity Framework but I think it results in a nice clean solution and the extra work has proven beneficial. In my final post in this Dapper series I will discuss the benefits of using Dapper and whether or not I think it should be replacing Entity Framework.
As always if you want to change/improve upon the solution I've discussed feel free to grab the latest version from my GitHub page here and fork the repository.