In this post we will look at migrating from a flat class to a hierarchy of classes.

Given the following situation:

We need to map specific properties for specific subclasses, but the biggest challenge is how to tell NHibernate which subclass to instantiate on load. In the old situation to differentiate between a RiverWeir and a SimpleWeir, one had to check the WeirType (string) property.

In the past, WeirType could contain the following strings:

  • simple_weir
  • river_weir
  • advanced_river_weir

We want NHibernate to use this property to decide which subclass to create, and we want to map both 'river_weir' and 'advanced_river_weir' to the RiverWeir class.

Let's first assume we don't have this 'advanced_river_weir'. In that case we can use the normal discriminator system of NHibernate (note: discriminator must come after Id!). We also map the specific properties while we're at it:

Migrating HBM for just 'simple_weir' and 'river_weir'
  <class name="Weir">
    <id name="Id">
      <generator class="guid" />
    </id>

    <discriminator column="WeirType"/>

    <property name="Name" />
    <property name="CrestLevel" />
    <property name="GateHeight" />
    
    <subclass name="SimpleWeir" discriminator-value="simple_weir" >
      <property name="DischargeCoefficient" formula="SimpleWeirDischargeCoefficient" />
    </subclass>

    <subclass name="RiverWeir" discriminator-value="river_weir" >
      <property name="SubmergeReduction" formula="RiverWeirSubmergeReduction" />
    </subclass>    
  </class>  

Now lets look at the more complex situation with 'advanced_river_weir' included. Again, formula comes to the rescue, this time in 'discriminator'. This way you can influence the value of what NHibernate sees as the discriminator value. The possible discriminator values you return must match with the discriminator-value's you supply for each subclass:

Migrating HBM 'simple_weir', 'river_weir' and 'advanced_river_weir'
  <class name="Weir">
    <id name="Id">
      <generator class="guid" />
    </id>

    <discriminator formula="case when WeirType in ('river_weir', 'advanced_river_weir') then 'RiverWeir' else 'SimpleWeir' end"/>

    <property name="Name" />
    <property name="CrestLevel" />
    <property name="GateHeight" />
    
    <subclass name="SimpleWeir" discriminator-value="SimpleWeir" >
      <property name="DischargeCoefficient" formula="SimpleWeirDischargeCoefficient" />
    </subclass>

    <subclass name="RiverWeir" discriminator-value="RiverWeir" >
      <property name="SubmergeReduction" formula="RiverWeirSubmergeReduction" />
    </subclass>    
  </class>  

Note that I have changed the discriminator-value of both subclasses and also in the discriminator formula, to indicate you can choose any.

For source code: https://repos.deltares.nl/repos/delft-tools/trunk/shared/NHibernateBackwardsCompatibility

  • No labels