When you have the need to modify or change your NHibernate mappings at runtime the obvious choice would be to go for one of a new generation mapping engine (like ConfORM, Fluent NHibernate, or anything else), but what about you plain good old XML mapping files you still use?

Changing them was a nightmare before NHibernate 3...I gave up on the task when I thought I had to pre-load the XML files, parse them, modify them in memory and the feed them to NHibernate; these operations seemed too long and too ‘hacky’ for a task that should have been simple.

NHibernate 3 comes to the rescue and offers a nice couple of events you can use to inspect and change your mapping before and after they are accepted and bound to be used by the configuration object:

  • BeforeBindMapping(object sender, BindMappingEventArgs) - this event is raised before the mapping is actually tied to the configuration object, you can inspect the mapping properties and change their values. Once the mapping is bound it becomes immutable.
  • AfterBindMapping(object sender, BindMappingEventArgs) - this event is raised after the mapping is bound to the configuration object, you can use it to inspect the metadata and get some information.

Using these events you have a chance to alter the mapping (acting directly with the NHibernate metadata structures) at runtime, whatever is the mapping method you chosen; in fact these events will be fired when you add the mappings to the NHibernate Configuration object via configuration.AddAssembly(), configuration.AddDeserializedMapping() and so on...

All the information are encapsulated in the BindMappingEventArgs class, which is something like this:

public class BindMappingEventArgs : EventArgs
{
	public NHibernate.Dialect.Dialect Dialect { get; private set; }

	public string FileName { get; private set; }
	
	public HbmMapping Mapping { get; private set; }
}

Dialect: the currently used NHibernate dialect and it gives you information about the currently used database engine.

FileName: if you use XML mapping files it’s the filename form which the mapping was parsed, otherwise it’s the value you specified in the ‘documentFileName’ parameter when using AddDeserializedMapping() or similar.

HbmMapping: is the internal deserialized representation of the mapping that NHibernate uses, these are the structures you will interact with when inspecting and changing your mappings at runtime.

Using these two events doing something like changing the schema of all the mappings at runtime to switch between a production and a test environment is a matter of few lines of code:

public Configuration SetupNHibernate()
{
	var configure = new Configuration();

	// configure NHibernate here
	// ...
	
	configure.BeforeBindMapping += configure_BeforeBindMapping;
	configure.AfterBindMapping += configure_AfterBindMapping;
	
	return configure;
}

void configure_AfterBindMapping(object sender, BindMappingEventArgs e)
{
	// inspect your mapping here
}

void configure_BeforeBindMapping(object sender, BindMappingEventArgs e)
{
	// some metacode that shows you how to change the mappings
	if (production)
		e.Mapping.schema = "Production.dbo";
	else
		e.Mapping.schema = "Test.dbo";
}

Beware that NbmMapping can contain a very complex series of nested structures, depends on how complex your mappings are...just experiment with it to see how it works.

This is another cool feature you can have with NHibernate 3.

Related Content