nhibernateusertypecompositeusertype

nhibernate user type composition


Say I have an immutable ICompositeUserType to deal with a DateRange, or Money, and then it turns out that I have another value object (ie, immutable) that has either a DateRange or Money property value in it. For example, a Name that has an EffectivePeriod (DateRange).

The DataRangeUserType encapsulates some logic I wouldn't want duplicated.

Can I reuse my DataRangeUserType inside of a NameUserType? How?

Cheers,
Berryl

UPDATE

Below is the summary comment on ICompositeUserType taken from the NHibernate source code which suggests what I am thinking of can be done, just not sure how. Admittedly, the component strategy is easy and works great, until you think you might want to use the same compoent elsewhere

/// <summary>
/// A UserType that may be dereferenced in a query.
/// This interface allows a custom type to define "properties".
/// These need not necessarily correspond to physical .NET style properties.
///
/// A ICompositeUserType may be used in almost every way
/// that a component may be used. It may even contain many-to-one
/// associations.
///
/// ...
/// </summary>

Using component mapping

<component name="MyCompositeComponent" class="...">

  <property name="Name" not-null="true" length="50"/>

  <property name="Price" type="...MoneyUserType">
      <column name="Amount"/>
      <column name="Currency"/>
  </property> 

  <property name="EffectivePeriod" type="...DateRangeUserType">
      <column name="EffectiveStart"/>
      <column name="EffectiveEnd"/>
  </property> 

</component>    

Solution

  • Hibernate lets you compose value types in Components:

    <class name="MyClass" table="MyTable" >
      ...
      <component name="_namedPeriod">
    
          <property name="_name" column="PeriodName" />
    
          <property name="_effectivePeriod" 
                    type="MyNamespace.DataRangeUserType, MyAssembly" >
    
              <column name="PeriodStart" />
              <column name="PeriodEnd" />
          </property>
    
      </component>
      ...
    </class>
    

    Classes look like this:

    // entity
    public class MyClass {
        private NamedPeriod _namedPeriod;
    }
    
    // immutable value object
    public class NamedPeriod {
        private readonly String _name;
        // immutable value object
        private readonly DateRange _effectivePeriod;
    }
    

    The idea that you use UserTypes for primitives like DateRange and Money and Component for a larger immutable value objects. Components can also include other components.