LA.NET [EN]

Sep 26

NHibernate and value objects

Posted in C# NHibernate      Comments Off on NHibernate and value objects

I do love NHibernate but there’ some things that keeps bothering me: value objects. Yes, NH does support it, but it seems like it’s impossible for having inheritance mapping when you decide to use them. There are some scenarios where inheritance makes sense, even when you’re thinking about value objects. For instance, lets think about contacts…You can probably represent a contact through an instance of type Contact, that could look like this (yes, this is a really simple example):

public class Contact{
  private Contact(){}
  public Contact(String value, ContactKind kind ){ … }
  public ContactValue{ get; private set; }
  public ContactKind{ get; private set; }
}

Where ContactKind could be an enumeration that looks like this:

enum ContactKind{
   Phone,
   Email
}

Ok, you could then have an entity which had a Contacts property that, in practice, would be a collection of value objects. This is a supported scenario by NHibernate. However,suppose that you want to have a more explicit API and that’s why you end up changing Contact to:

public class Contact{
  private Contact(){}
  public Contact(String value){ … }
  public ContactValue{ get; set; }
  protected abstract ContactKind{ get; }
}

So that you could introduce a specific type for each kind of contact. Here’s an example for phone:

public class Phone{
  public Phone(String value) : base (value ){ }
  protected override ContactKind{ get{return ContactKind.Phone} }
}

This kind of change will better express my domain and it will let me do further improvements on the base class (for instance,now I can add validation to the constructor so that I always know that the passed in phone number is valid).

Now, unfortunatelly, NH won’t give me any support for mapping this scenario into a table (ok, if there is a way, please let me know). If you want to do that, you’ll have to add an ID to your contact class and you’ll have to transform it into a component (ok, you can mask this so that only NH sees Contact as an entity). Is this such an exotic scenario that I probably shouldn’t be using it? I think not, but I may be wrong…