tags:

views:

46

answers:

4

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.

A: 

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

Spencer Ruport
Nice idea using T4, but I still have to add the same nine properties to all of my entities, this what I want to avoid.
Ian Oakes
I guess I'm not seeing the issue so long as you only have to edit the nine properties in one place.
Spencer Ruport
I'm not worried about the editing the mapping files, you suggested T4 I've used code snippets, my question is...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 repeating columns in each of the classes in the domain model?
Ian Oakes
A: 

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.

Diego Mijelshon
+2  A: 

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
}
Jamie Ide
A: 

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>
Ian Oakes