Dynamic Mapping with NHibernate

A while ago I posted how to handle dynamic mapping with Active Record, it was incredibly easy to do, because Active Record has a lot of smarts internally, and output the XML, on top of which NHibernate adds quite a bit of convention over configuration as well. Doing the same using NHibernate directly is possible, but a bit long winded. Here is the sample code, which link all the Employee properties to the correct entity:

Configuration cfg = new Configuration()
    .AddAssembly(typeof (Employee).Assembly)
    .AddAssembly(typeof(ScheduledTask).Assembly);
Mappings mappings = cfg.CreateMappings();
foreach (PersistentClass persistentClass in mappings.Classes)
{
    if (persistentClass.MappedClass.GetProperty("Employee") == null)
        continue;
    Property prop = new Property();
    PersistentClass employeeClass = cfg.GetClassMapping(typeof (Employee));
    Table table = employeeClass.Table;
    ManyToOne value = new ManyToOne(table);
    value.ReferencedEntityName = typeof (Employee).FullName;
    Column column = new Column("Employee");
    value.AddColumn(column);
    prop.Value = value;
    prop.Name = "Employee";
    prop.PersistentClass = employeeClass;
    persistentClass.AddProperty(prop);
    persistentClass.Table.AddColumn(column);
    persistentClass.Table.CreateForeignKey("FK_EmployeeTo" + persistentClass.MappedClass.Name,
                                           new Column[] {column,}, typeof (Employee).FullName);
}
cfg.BuildSessionFactory();
new SchemaExport(cfg).Execute(true, true, false, true);

As you can see, there is a lot that needs to be done, we have to tell NHibernate a lot of things it would generally be able to figure out on its own. We can shove this to an extension method and get really nice syntax:

public static void MapManyToOne<TEntityInterface, TEntity>(this Configuration cfg)
{
    Mappings mappings = cfg.CreateMappings();
    foreach (PersistentClass persistentClass in mappings.Classes)
    {
        var propertyNames = new List<string>();
        foreach (PropertyInfo property in persistentClass.MappedClass.GetProperties())
        {
            if (property.PropertyType == typeof (TEntityInterface))
            {
                propertyNames.Add(property.Name);
            }
        }
        if (propertyNames.Count == 0)
            continue; 

        var prop = new Property();
        PersistentClass targetClass = cfg.GetClassMapping(typeof (TEntity)); 

        foreach (string propertyName in propertyNames)
        {
            Table table = targetClass.Table;
            var value = new ManyToOne(table);
            value.ReferencedEntityName = typeof (TEntity).FullName;
            var column = new Column(propertyName);
            value.AddColumn(column);
            prop.Value = value;
            prop.Name = propertyName;
            prop.PersistentClass = targetClass;
            persistentClass.AddProperty(prop);
            persistentClass.Table.AddColumn(column);
            string fkName = string.Format("FK_{0}To{1}", propertyName, persistentClass.MappedClass.Name);
            persistentClass.Table.CreateForeignKey(fkName,
                                                   new[] {column,}, typeof (TEntity).FullName);
        }
    }
}

Now we can use this with the following syntax:

cfg.MapManyToOne<IEmployee, Employee>();

Which is much nicer.

Print | posted on Thursday, May 01, 2008 1:21 PM

Feedback


Gravatar

# re: Dynamic Mapping with NHibernate 5/1/2008 5:58 PM Kevin Williams

Nicely done.


Gravatar

# re: Dynamic Mapping with NHibernate 5/1/2008 9:04 PM Chris Ortman

Is the other post you are referring to this one
http://ayende.com/Blog/archive/2008/01/11/Active-Record-Mapping-Rewriting.aspx
or is was there another?


Gravatar

# re: Dynamic Mapping with NHibernate 5/1/2008 9:45 PM Ayende Rahien

Yes, that is the post


 re: Dynamic Mapping with NHibernate 5/2/2008 11:26 AM Stuart C

What version of Nhibernate are you using? I'm using 2.0 Alpha and NHibernate.cfg.Mappings does not have a 'Classes' property...


Gravatar

# re: Dynamic Mapping with NHibernate 5/2/2008 1:04 PM Ayende Rahien

It has now


# re: Dynamic Mapping with NHibernate 5/2/2008 6:09 PM Steve Gentile

Good stuff as always!


 re: Dynamic Mapping with NHibernate 5/12/2008 6:29 PM Jurnio

What version of Nhibernate are you using? I don't have a 'Classes' property...


Gravatar

 re: Dynamic Mapping with NHibernate 5/14/2008 11:49 PM THe

Good stuff. So it is possible to create the entities by dynamic xml schema.

Comments have been closed on this topic.