views:

1426

answers:

3

When would I write a UoW implementation on top of what is already provided by NHibernate? Any real world examples?

A: 

Provided you set up all your mappings correctly (i.e. cascades), you don't have to do anything special and ISession will do just fine. However, if you're writing a 3-tier application, you'll have to manually sequence database operations you want to be performed in a single transaction. Fowler's "reference implementation" in "Patterns of Enterprise Application Architecture" can be a good starting point:

class UnitOfWork... 

   public void registerNew(DomainObject obj) {
      Assert.notNull("id not null", obj.getId());
      Assert.isTrue("object not dirty", !dirtyObjects.contains(obj));
      Assert.isTrue("object not removed", !removedObjects.contains(obj));
      Assert.isTrue("object not already registered new", !newObjects.contains(obj));
      newObjects.add(obj);
   }
   public void registerDirty(DomainObject obj) {
      Assert.notNull("id not null", obj.getId());
      Assert.isTrue("object not removed", !removedObjects.contains(obj));
      if (!dirtyObjects.contains(obj) && !newObjects.contains(obj)) {
         dirtyObjects.add(obj);
      }
   }
   public void registerRemoved(DomainObject obj) {
      Assert.notNull("id not null", obj.getId());
      if (newObjects.remove(obj)) return;
      dirtyObjects.remove(obj);
      if (!removedObjects.contains(obj)) {
         removedObjects.add(obj);
      }
   }
   public void registerClean(DomainObject obj) {
      Assert.notNull("id not null", obj.getId());
   }
Anton Gogolev
It is a 3 tier app. However, we want each user request to be atomic, therefore 1 user request = 1 DB transaction. I'll process the user request, modify the domain objects, and then ask NHibernate to persist my aggregate root.
ng5000
This is an abstraction over an identitymap. It's useful when you create manual datamapping as described in Fowler's POEA, but with NHibernate, because the identitymap is build in to the ISession.
Paco
+4  A: 

The Unit Of Work you are describing is already provided by NHibernate so there is no reason to do such a unit of work.

What we have in our WCF Service is a higher level unit of work that contains information important in our application for the current unit of work. This includes abstracting the NHibernate ISession for us. When you break it down you have code that fits into three categories

  1. Code that needs to deal with a Unit Of Work. It doesn't matter who backs the unit of work. It could be NHibernate, iBatis or a custom ORM. All the code needs to do is Load, Rollback, Save, etc. It doesn't nor should it care about the mechanism used to do so.

  2. Code that needs to deal with an ISession directly because it's doing NHibernate specific things. Usually this has to do with complex queries that need to be created.

  3. Doesn't need to know that it's running in a Unit Of Work or access the ISession. We can completely ignore this as part of this discussion.

While code in 1. could just work against an ISession our preference is to try to abstract away things in the code that we do not directly control or that could change. This has value for two reasons.

  • When we started we weren't 100% sold on NHibernate. We were considering iBatis or something custom. Obviously this is no longer an issue.

  • The entire team are not experts in NHibernate nor do we want them to be. For the most part people write code that fits into category 1. and all they know about is our Unit Of Work. When code in category 2. has to get written it gets written by the people on the team that understand NHibernate well.

So to close I would say that the type of Unit Of Work you are talking about is not needed I would suggest that a higher level Unit of Work can provide a lot of value.

ShaneC
ShaneC, I have a similar question, and it sounds like you have created a Unit of Work that fits my needs better than mine. Can you take a look at my question and offer your $0.02?http://stackoverflow.com/questions/2604762/using-unit-of-work-design-pattern-nhibernate-sessions-in-an-mvvm-wpf
Echiban
+1  A: 

My basic unit of work interface contains the following methods - Initialize - Commit - Rollback - IDisposable.Dispose

I use it for both session and transaction management. It is useful because I don't have to write that code again and again for different session scopes. (unit of work per request, per series of requests, per thread, etc)

Paco
Can you post an example?
David P
What kind of example? using the unit of work or the unit of work itself?
Paco