Thursday, March 05, 2009

Domain Objects with Validation in Fluent NHibernate

Here is an issue that took me quite some time to figure out how to resolve it. I am experimenting with Fluent NHibernate. My starting point was that I wanted the code of my domain classes squeaky clean: Not a single hint that they may become persistent. Why? I wanted to have the domain free from anything that has nothing to do with the domain. At the same time I wanted the domain model to contain the validation code. Ok, I know the way I implemented validation is not necessarily in line with the usual approach in NHibernate. But let's have a look at my domain class:
   internal class WorkItem {
      public WorkItem () {
      }

      public virtual long Id {
         get {
            return _id;
         }
         set {
            _id = value;
         }
      }

      public virtual string Title {
         get {
            return _title;
         }
         set {
            _title = Validation.EnsureNonEmptyString(value, "Title");
         }
      }

      private long _id;
      private string _title = "";
   }
I left most of it out. For now let's look at just the id and the title since those two demonstrate sufficiently the issue. What you will notice is that the setter for the title contains validation code ("Validation.EnsureNonEmptyString(...)"). The problem starts when you query for one or more WorkItem's. Then NHibernate will use the property setters to initialize the instance of WorkItem. For strings the default value is null (nothing in VB.NET). With the given code, however, the validation will throw an exception since that is what it is designed to do. It doesn't care whether the setter is called by NHibernate or anything else. So next I tried to figure out what alternatives I would have for validation and I found NHibernate.Validator. Although a step in the right direction I didn't like that the client code for the domain objects would have to explicitly call the validation. Alternatively the validation would have to be invoke via the event call backs from NHibernate. In both cases the domain class would only work properly if something else would collaborate. I didn't like that concept and started to look for an alternative. And there is a quite simple solution to this: Change the configuration for NHibernate so that it doesn't use the properties to initialize the domain objects. This configuration change can be done via Fluent NHibernate as follows:
       _hibernateConfig = new Configuration();
         AutoPersistenceModel persistenceModel = 
            AutoPersistenceModel
            .MapEntitiesFromAssemblyOf()
            .Where(TypeIsIncluded)
            .ForTypesThatDeriveFrom(
               map => map
                  .DefaultAccess
                  .AsCamelCaseField(Prefix.Underscore));
         persistenceModel.Configure(_hibernateConfig);
Depending on your naming conventions you may want to use a different access strategy or a different Prefix value. In my case it was Camel Casing with an underscore as a prefix. After I finally found this solution I was able to keep the domain classes squeaky clean and at the same time stay with using the Fluent NHibernate interface and avoiding exception during the initialization of instances of domain classes. Of course I'm not sure whether this is the only and/or best option. If you have other options that are even better, please drop me a note. I'm always keen to learn more!

0 comments:

Post a Comment

All comments, questions and other feedback is much appreciated. Thank you!