Battle of the ORM’s – Persistence
The last thing I will compare in this round of Battle of the ORM’s is how NHibernate and the Entity Framework handle persistence. So first of all I want to vent one of my pet peeves, which is the myth of persistence ignorence.
Persistence ignorence is a term used to describe a persistence mecanism that does not contaminate the domain model and hence the business logic. This means that the model can be ignorent of how it is stored and not contain detals about the datastore. I think this a very important design goal to strive for, however actually obtaining true ignorence is a myth and something no ORM is even close to achieving.
Why? Working with transactions, caching, managing contexts between threads or making the application perform will to some extent leak into your business logic – period. Transactions may very well require managing more than just changes to a single database. Efficient successful caching strategies depend on business logic. Threading requires contexts and transactions to be managed. Making an application perform will require you to avoid n+1 issues and make decisions on lazy loading. And the list goes on, but this should give some ideas.
So besides having metadata for mappings described in separate classes or xml, and not as attributes on classes and properties, is often what is meant when something is called “persistence ignorent”. To me it the key point is about reducing how much the before meantioned technical concerns leak into the logic. Basically making it natural to do the simple stuff right and easy to handle special cases when needed.
Many ways to skin a cat
It should come as no surprise that what you need in order to manage data in an ORM is the ability to save, update and delete objects. Naturally both NHibernate and Entity Framework provide functionality to do this, but the API’s are really quite different.
Save, Update, Delete with NHibernate
With NHibernate you have a bunch of methods that allow you to make changes to the data, which all are accessed on the session object. Save, SaveOrUpdate, SaveOrUpdateCopy and Update are all ways of saving objects. SaveOrUpdateCopy allows you to save or update an object that is not in the cache based on its identifier – the rest should be self explanatory. To delete an object there is a Delete method, so it is as easy as can be, but a little wierd there is no DeleteCopy to keep the API symmetric.
Calling either of these methods will not make any changes to the database right away. The changes happen when the session is flushed. This can be done in different ways by setting the FlushMode to: Always, Auto, Commit, Never. Always means before every query – so it is almost never used because it hurts performance. Auto means sometimes before a query – enough to avoid stale data. Commit means when the transaction is commited. Never means you do it manually by calling the Flush method.
Merge and Evict methods can be used to merge the state of an object in to the persisted object with the same identifier, and to remove an instance from the session cache.
For some scenarios, like batch creation, NHibernate offers a StatelessSession class that does not keep track of changes. This gives you Insert, Update and Delete methods to do means a little less overhead, and that you can actually make changes to the same object instance and then when it is saved you get a new row in the database.
Save, Update, Delete with Entity Framework
The API for the Entity Framework is quite a bit more lean, because what you have is Add, Remove and Attach methods on the DbSet class. Just as a reminder the DbSet is what we used to define that we have a table/collection of eg. Companies. Add and Remove hardly require any explanation, but Attach is used to tell the context to keep trach of changes to an object that are currently not tracked. This could tyically be objects that did not originate from a query on that session or that have been passed over a webservice.
Just as NHibernate requires a flush for changes to be persisted, Entity Framework requires SaveChanges on the DbContext to be called. This is the reason for the Attach method, because changes are tracked by the session, allowing it to do updates even though there is no specific Update method. If you wish to do a query and get objects back that are not tracked this can be done with the method called AsNoTracking.
So the API for the Entity Framework is simpler to get started with, and there are less things you need to know about. With NHibernate you gain a little more control, but I have a hard time thinking of something I will really gain. After all if I wish to better my performance I would probably rather write some SQL myself before looking at batch updates using the StateLessSession.
Transactions – scopes and pitfalles
A very important concept that most of us can not do without are transactions. This is simply because we need to do several changes and remain confident that the data will be consistent.
NHibernate has its own Transaction class, and it is recommended as a best practice to always handle the transactions yourself like so:
using (var transaction = session.BeginTransaction())
// Do stuff
In the same way the .NET framework offers a TransactionScope that can be used in this way:
using (TransactionScope scope = new TransactionScope())
// Do stuff
However in some cases you need to combine the two when using NHibernate, eg to use TransactionScope for distributed transactions. The reason I include this topis is that there is a pitfall you need to be aware of. The Session, TransactionScope and NHibernates transaction must be opened and closed in a particular order – otherwise you may end up leaking connections.
Open order: TransactionScope – Session – NHibernate Transaction
Close order: NHibernate Transactions – Session – TransactionScope
So the right way to do it is something like:
using (var scope = new TransactionScope(TransactionScopeOption.Required))
using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
var result = session.Query<Company>().ToList();
After having written these three posts on NHibernate and Entity Framework, I feel like Entity Framework will be the primary tool for me to go once it reaches RTM. I have been happy with NHibernate, but I feel life is simpler with the Entity Framework, and that the more solid LINQ provider will help me sleep more comfortably at night.
That being said I have no doubt there is room for both in the .NET world, and that there will be pleanty of religious discussions on the subject. When all is said and done I can only advise you to get to know both and use the right tool for the right job.