Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

This is part two in the series describing how to write a 'legacy'/'migrating' hbm for backward compatibility.

The refactoring in this post is the splitting of a class 'Bridge'. See the class diagram:

Originally there was one big Bridge class, but later it was decided to split it into a Bridge and a BridgeDefinition. Also the properties don't exactly match:

  • SideArea: no longer exists
  • Pillars -> renamed to NumPillars
  • Color: should always be 'RED'
  • IsOpen: new

Here are the old HBM (for reference) and the new HBM:

Section
bordertrue
Column
width50%
Code Block
titleOld HBM
  <class name="Bridge">
    <id name="Id"> <generator class="guid" /> </id>
    <property name="Name" />
    <property name="Color" />
    <property name="HasRoad"/>
    <property name="Width"/>
    <property name="Height"/>
    <property name="SideArea"/>
    <property name="Type"/>
    <property name="Pillars"/>
  </class>
Column
width50%
Code Block
titleNew HBM
  <class name="Bridge">
    <id name="Id"> <generator class="guid" /> </id>
    <property name="Name" />
    <property name="Color" />
    <property name="HasRoad"/>
    <property name="IsOpen"/>
    <many-to-one name="Definition" cascade="all-delete-orphan"/>
  </class>

  <class name="BridgeDefinition">
    <id name="Id">
      <generator class="guid" />
    </id>
    <property name="Type"/>
    <property name="Width"/>
    <property name="Height"/>
    <property name="NumPillars"/>
  </class>

We need to tackle four property changes and the class split itself. Let's start with the property changes:

Property

Change

Solution

SideArea

No longer exists

Do nothing!

Pillars

Renamed to NumPillars

No Format
<property name="NumPillars" formula="Pillars"/>

Color

Should always be 'RED' when loading old data

No Format
<property name="Color" formula="'RED'"/>

IsOpen

New property, should always be 'true' when loading old data

No Format
<property name="IsOpen" formula="1"/>

Finally we need to tackle how to split the class. Fortunately NHibernate has something called components, where it persists two classes into one table. We just tell NHibernate to threat the table as such a table, with BridgeDefinition being a 'component' of Bridge and NHibernate will load the single table into two entities, just like we want. The resulting HBM looks like this:

Code Block
titleMigrating HBM
  <class name="Bridge">
    <id name="Id"> <generator class="guid" /> </id>
    <property name="Name" />
    <property name="Color" formula="'RED'"/>
    <property name="HasRoad"/>
    <property name="IsOpen" formula="1"/>

    <component name="Definition" class="BridgeDefinition">
      <property name="Type"/>
      <property name="Width"/>
      <property name="Height"/>
      <property name="NumPillars" formula="Pillars"/>
    </component>
  </class>

Note that the Id property of the BridgeDefinition component is not mapped. However when saving this class in the new session (with the new hbm's), it will receive an Id anyway.

The resulting SQL:

No Format
SELECT bridge.Id, bridge.Name, bridge.HasRoad, bridge.Type, bridge.Width, bridge.Height, 'RED', 1, bridge.Pillars FROM Bridge bridge WHERE bridge.Id=...

Note that the splitting into a component is handled by NHibernate in code and has no effect on the SQL.

Hopefully this post shows that what appears to be a more difficult refactoring, turns out to be pretty easily mapped. See previous post for SVN link to source code. Next up: class merge.