Search code examples
nhibernatenhibernate-mapping

Nhibernate: one-to-one to one-to-one


I have the following UML structure:

enter image description here

I'm trying to map it similar to this:

<class name="Parent" table="ParentTable">
    <id name="Id">
        <generator class="guid.comb" />
    </id>
    <one-to-one name="Child" class="IChild" property-ref="Parent" cascade="all" />
</class>

<class name="IChild" table="ChildTable" abstract="true">
    <id name="Id">
        <generator class="foreign">
            <param name="property">Parent</param>
        </generator>
    </id>   
    <discriminator column="TypeKey" type="String"/>
    <one-to-one name="Parent" class="Parent" />
    <one-to-one name="Child" class="IGrandchild" property-ref="Parent" cascade="all" />
</class>

<subclass name="ConcreteChild" extends="IChild" discriminator-value="ConcreteChild1">
  <property name="SomeProperty"/>
</subclass>

<class name="IGrandchild" table="GrandchildTable" abstract="true">
    <id name="Id">
        <generator class="guid.comb" />
    </id>
    <discriminator column="TypeKey" type="String"/>
    <many-to-one name="Parent" class="IChild" unique="true" column="ChildTableFk" />
</class>

<subclass name="ConcreteGrandchild" extends="IGrandchild" discriminator-value="ConcreteGrandchild1">
  <property name="SomeOtherProperty"/>
</subclass>

Working against SQL this doesn't work (strangely, with SQLite this does work). NHibernate first inserts the Parent with the generated guid. It then inserts the child with the same guid. But when it comes to inserting the grandchild, it inserts it with ChildTableFk null (and never attempts to update the FK value).

Additional points:

  • I prefer not changing the IChild mapping to use many-to-one with FK if possible (I prefer a shared PK).
  • I can't change the IGrandChild mapping to use a foreign generator because the grandchild can be changed after the object graph is changed, which NHibernate does not support with a foreign generator (an IChild instance, on the other hand, will never change for the lifecycle of a given IParent).

Other than that, any suggestions are welcome, including alternate mapping styles (as long as they support polymorphic IChild and IGrandchild objects).


Solution

  • Oops, seems that I just forgot to set the Parent property on the Grandchild. Should have been the first thing I looked at.