Fluent nhibernate: how do I map an object to a property whose type is an interface?

I have an object like:

public class Employee { public int ID { get; set; } public IAccountManager AccountManager { get; set; } ... } 

I also have a mapping defined for "DefaultAccountManager" - a specific implementation of IAccountManager. When matching the Employee entity, how can I tell NHibernate to save / load the AccountManager property using the mapping defined in the DefaultAccountManager?

Edit: In fact, if I could set up a mapping for IAccountManager so that NHibernate could just indicate which implementer would load / save, that would be even better. I would prefer not to violate polymorphism, forcing all artists to use the same mapping.

+3
source share
3 answers

I found the answer to this question. I am a bit unclear in the details, as it was a few months ago, but the following was a crazy solution:

  • Create a table for each IAccountManager implementation that has mappings.
  • Make sure your database is configured to use the HiLo identifier algorithm.
  • Use union-subclasses in your mappings

Union subclasses look something like this:

 <class name="IAccountManager" abstract="true"> <id name="ID" column="ID" type="Int32"> <generator class="hilo"/> </id> <union-subclass name="DefaultAccountManager" table="DefaultAccountManager" proxy="IAccountManager"> <property name="FirstName" type="String"/> <property name="LastName" type="String"/> </union-subclass> ... more implementations </class> 

Note the "name" attribute in union-subclass. This must be unique to (and conformance to) each IAccountManager implementation.

In addition, an identifier, not unique to each table, will be unique to all IAccountManagers (by using hilo).

When NHibernate sees an IAccountManager object, it will use the specific instance type and union-subclass definitions to figure out the correct table.

Hope this helps!

+4
source

I just thought that I would share the way I was able to achieve this using Fluent NHibernate and not hbm files.

This method is a bit hacky, but the hacks are isolated and easily removed as soon as Fluent NH gets proper support for the Union subclass.

To use your example, the context of my scenario is as follows: the Employee class is in one project with the AccountManager property specified as an interface, because a specific AccountManager is in another project that we do not want to create a dependency on.

First, I create a helper class that does most of the Employee display and looks like this.

 public abstract class EmployeeMapperBase { protected abstract Type GetAccountManagerType(); public void DoMapping(ClassMap<Employee> classMap) { classMap.Id(x => x.Id); classMap.Maps(..... etc.... classMap.References(x => x.AccountManager) .Class(GetAccountManagerType()); } } 

Then, in the project with the specific AccountManager class, I will complete the mapping:

 public class EmployeeClassMap : ClassMap<Employee> { public EmployeeClassMap { new ConcreteEmployeeMapper().DoMapping(this); } private class ConcreteEmployeeMapper : EmployeeMapperBase { public override Type GetAccountManagerType() { return typeof(DefaultAccountManager); } } } 
+1
source

If you need polymorphism, because the IAccountManager implementation functionality may have different functionality, you can look at discriminators and use the base class of the interface instead.

If you just use the interface, because this is the OOP du jour paradox, then think twice about it, since entities that usually carry almost no behavior, the interface provides little - if any - value in this situation.

0
source

All Articles