Ian Oakes
Ian Oakes

Reputation: 10253

How do I map repeating columns in NHibernate without creating duplicate properties

Given a database that has numerous repeating columns used for auditing and versioning, what is the best way to model it using NHibernate, without having to repeat each of the columns in each of the classes in the domain model?

Every table in the database repeats these same nine columns, the names and types are identical and I don't want to replicate it in the domain model.

I have read the docs and I saw the section on inheritance mapping but I couldn't see how to make it work in this scenario. This seems like a common scenario because nearly every database I've work on has had the four common audit columns (CreatedBy, CreateDate, UpdatedBy, UpdateDate) in nearly every table. This database is no different except that it introduces another five columns which are common to every table.

Upvotes: 0

Views: 591

Answers (4)

Ian Oakes
Ian Oakes

Reputation: 10253

This can be accomplished by using the component element in the mapping file.

The basic idea is to create a class to hold the common properties and reference it from each of the entities in your model.

Then inside your mapping file add a reference to this property like this...

<component name="RecordMetadata" class="RecordMetadata" insert="true" update="true">
    <property name="UpdatedBy" />
    <property name="UpdatedDate" />
    <property name="CreatedBy" />
    <property name="CreatedDate" />
</component>

Upvotes: 0

Jamie Ide
Jamie Ide

Reputation: 49251

Use Fluent NHibernate to create your mapping files. This allows you to use inheritance with your mapping files. For example:

public class AuditableClassMap<T> : ClassMap<T> where T : IAuditable
{
    public AuditableClassMap()
    {
        Map(x => x.CreatedBy);
        Map(x => x.CreatedDate, "CreatedDt");
        Map(x => x.RevisedBy);
        Map(x => x.RevisedDate, "RevisedDt");
    }
}

public class CompanyMap : AuditableClassMap<Company>
{
    // mapping for Company
}

Upvotes: 2

Diego Mijelshon
Diego Mijelshon

Reputation: 52745

Instead of mapping by hand, use ConfORM.

In many cases, it will do all the work for you. When it doesn't, it's very easy to define your conventions and overrides.

Upvotes: 0

Spencer Ruport
Spencer Ruport

Reputation: 35107

Using t4 code generation you should be able to write a single code generation file that outputs a single .hbm.xml file with all of your classes defined. I envision something like the following. First, create a file with the .tt extension and put in the following code:

<#@ template language="C#v3.5" #>
<#@ output extension="hbm.xml" #>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="MyNameSpace">
<#
System.Collections.Generic.Dictionary<string, string> classes = new System.Collections.Generic.Dictionary<string, string>();
classes.add("RootNameSpace.SubNameSpace.MyClass1", "Table1");

foreach(string className in classes.keys)
{
#>
  <class name="<#=className#>, AssemblyName" table="<#=classes[className]#>">
    <id name="ID" column="EntityID" type="Int32">
      <generator class="native" />
    </id>
    <property name="Property1" />
    <property name="Property2" />
  </class>
<#
}
#>
</hibernate-mapping>

The last step would be to set the output file's Build Action to Embedded Resource and you should be good to go.

You can read more about t4 code generation here: http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx

Upvotes: 0

Related Questions