Ang3lFir3 – Life as a Code Poet

August 6, 2009

Table Per Subclass Inheritance Mapping with Fluent nHibernate

Filed under: .NET, C#, Fluent NHibernate, NHibernate, ORM, Patterns — Tags: , , , , , , — ang3lfir3 @ 2:45 pm

Note: Updates for Fluent nHibernate 1.0 RC can be read here

This is the third in a short series of posts I am working on. While reading through NHibernate in Action I thought to my self that I should create these same examples of Inheritance mapping using Fluent nHibernate to show how simple these mappings can be.

The three types of Inheritance mappings that are mentioned on page 92 of NHibernate in Action are :

Model

  • Table Per Concrete Class
  • Table Per Class Hierarchy
  • Table Per Subclass

I will be using the example from NHibernate in Action to illustrate the mappings. This post covers the Table Per Subclass example. In Table per Subclass inheritance mapping we represent inheritance by using a foreign key to join tables together as needed.  This most closely represents the object model in the relational model of the database by using a table for the base class and one for each subclass.

TablePerSubclassFiles

Here you can see that again I only have one mapping file which covers the entire class Hierarchy.

Below you can see the Fluent Mappings for this approach. The JoinedSubClass<T> uses the Type as the table name by default (“CreditCard” and “BankAccount”) and the first parameter of the method is the name to use for the foreign key column. Additionally the mapping for the class being joined is included.

  public class BillingDetailsMap : ClassMap<BillingDetails>
  {
    public BillingDetailsMap()
    {
      Id(x => x.Id);
      Map(x => x.Number);
      Map(x => x.Owner);
      Map(x => x.DateCreated);
      JoinedSubClass<CreditCard>("CreditCard_Id", m =>
                                                    {
                                                      m.Map(c => c.Type);
                                                      m.Map(c => c.ExpirationMonth);
                                                      m.Map(c => c.ExpirationYear);
                                                    });
      JoinedSubClass<BankAccount>("BankAccount_Id", m =>
                                                      {
                                                        m.Map(b => b.BankName);
                                                        m.Map(b => b.RoutingNumber);
                                                      });
    }
  }

Which maps to the following nHibernate XML mapping file.

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="">
  <class name="TablePerSubclass.Model.BillingDetails, TablePerSubclass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`BillingDetails`" xmlns="urn:nhibernate-mapping-2.2">
    <id name="Id" type="Int32" column="Id">
      <generator class="identity" />
    </id>
    <property name="Number" type="String">
      <column name="Number" />
    </property>
    <property name="Owner" type="String">
      <column name="Owner" />
    </property>
    <property name="DateCreated" type="DateTime">
      <column name="DateCreated" />
    </property>
    <joined-subclass name="TablePerSubclass.Model.CreditCard, TablePerSubclass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <key column="CreditCard_Id" />
      <property name="Type" type="Int32">
        <column name="Type" />
      </property>
      <property name="ExpirationMonth" type="String">
        <column name="ExpirationMonth" />
      </property>
      <property name="ExpirationYear" type="String">
        <column name="ExpirationYear" />
      </property>
    </joined-subclass>
    <joined-subclass name="TablePerSubclass.Model.BankAccount, TablePerSubclass, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
      <key column="BankAccount_Id" />
      <property name="BankName" type="String">
        <column name="BankName" />
      </property>
      <property name="RoutingNumber" type="String">
        <column name="RoutingNumber" />
      </property>
    </joined-subclass>
  </class>
</hibernate-mapping>

And the corresponding Database Schema. I followed the naming from the NHibernate in Action so you can see here maybe this is a little confusing. But basicly the “BankAccount_Id” is the primary key of the BankAccount table and contains is also a foreign key to the BillingDetails table.

TablePerSubclassSchema

kick it on DotNetKicks.com

10 Comments »

  1. Sorry but that is not a real NH xml mapping. It is only the mapping generated by FNH.

    Comment by Fabio Maulo — August 7, 2009 @ 8:17 pm

    • what makes the hbm.xml files generated by FNH not actual nHibernate mapping files? I ask so that I can understand your comment.

      Comment by ang3lfir3 — August 8, 2009 @ 12:47 am

      • Fluent NHibernate’s generated HBM is more verbose than you’d normally create if writing it yourself. Properties don’t need the explicit column element. The type attribute is generally unneeded, and the joined-subclass name can just be the type name.

        Comment by James Gregory — August 8, 2009 @ 12:59 am

  2. [...] samples that I used in Table Per Class Hierarchy Inheritance Mapping with Fluent nHibernate and Table Per Subclass Inheritance Mapping with Fluent nHibernate I will show you the changes. Which are pretty simple and vary only slightly between the two [...]

    Pingback by Updates to Subclass and JoinedSubclass mapping in Fluent nHibernate 1.0 RC « Ang3lFir3 – Life as a Code Poet — August 17, 2009 @ 3:27 pm

  3. What if the subclass table name is different than the subclass object Name ?
    How can I Tell FNH that CreditCard data is in tblCreditCard ?

    my problem implementing this example is that it can’t find my table as it looks for a table name named CreditCard….
    10x.

    Comment by Dani — September 8, 2009 @ 9:22 am

    • in the JoinedSubclass Mapping (which is now obsolete : see my posts on the updates) you can use.

      JoinedSubClass<CreditCard>("CreditCard_Id", m =>
      {
      m.WithTableName("tblCreditCard");
      ......
      }

      You can also do this using an implementation of a convention if you always name tables with the “tbl” prefix.

      Comment by ang3lfir3 — September 8, 2009 @ 11:40 am

      • 10x, it solved my problem.
        Do you know what might be the difference using this method to solve the post’s case and using:
        DiscriminateSubClassesOnColumn ?
        Dani

        Comment by Dani — September 8, 2009 @ 11:46 pm

  4. Most of which is to be expected with xml being generated from code … but I would think they are still actual nHibernate mapping files. Just very verbose ones.

    Comment by ang3lfir3 — August 8, 2009 @ 1:06 am

  5. They are still mapping files, quite obviously. You’ll need Fabio to explain that one.

    Comment by James Gregory — August 8, 2009 @ 1:14 am

  6. @Dani

    DiscriminateSubClassesOnColumn is used for Table-Per-ClassHierarchy mapping. please see my other post regarding this topic.

    http://ang3lfir3.wordpress.com/2009/08/04/table-per-class-hierarchy-inheritance-mapping-with-fluent-nhibernate/
    and
    http://ang3lfir3.wordpress.com/2009/08/17/updates-to-subclass-and-joinedsubclass-mapping-in-fluent-nhibernate-1-0-rc/

    Comment by ang3lfir3 — September 9, 2009 @ 7:51 pm


RSS feed for comments on this post. TrackBack URI

Leave a comment

Blog at WordPress.com.