Days ago in one of my previous posts I talked about ConfORM, let’s see in this very short post how you can put it in action in a very simple test project.

We’ll start by creating a function to configure NHibernate:

private static Configuration ConfigureNHibernate()
{
	var configure = new Configuration();
	configure.SessionFactoryName("Demo");
	configure.Proxy(p =>
	{
		p.Validation = false;
		p.ProxyFactoryFactory<ProxyFactoryFactory>();
	});
	configure.DataBaseIntegration(db =>
	{
		db.Dialect<MsSql2008Dialect>();
		db.Driver<SqlClientDriver>();
		db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
		db.IsolationLevel = IsolationLevel.ReadCommitted;
		db.ConnectionString = ConnectionString;
		db.Timeout = 10;
		db.HqlToSqlSubstitutions = "true 1, false 0, yes 'Y', no 'N'";

		// enabled for testing
		db.LogFormatedSql = true;
		// db.LogSqlInConsole = true;
		// db.AutoCommentSql = true;
	});
	return configure;
}

Until now these are standard NHibernate configuration functions, let’s take a look at how we will map our domain using ConfORM; to keep this post short I will not show the domain classes here, you can see the full example in the attached download.

When it comes to ConfORM you have to deal mainly with two distinct objects:

  • The ObjectRelationalMapper: which will be used to inject your general mapping rules and patterns in the mapping engine and to define your domain mappings (what classes you want to map and how to map them); this object is used to define the basic shape of your mapping.
  • The Mapper: which will be used to define exceptions to the rules and special cases, to perform some mapping fine tuning and finally to apply the rules and generate an HbmMapping object we can feed to NHibernate.

Initializing and using ConfORM is simple:

  1. You need to create an instance of the ObjectRelationalMapper, optionally set some properties and patterns you want to use or not to use (you can skip this step if you want to keep the default configuration).
  2. You need to create an instance of the Mapper object (which will accept your ObjectRelationalMapper as first argument and a series of optional parameters that will be used to define some pattern appliers... more on this in a next post):
    var orm = new ObjectRelationalMapper();
    var mapper = new Mapper(orm);
  3. You can start defining your mapping using the functions exposed by the ORM object:
    // list all the entities we want to map
    IEnumerable<Type> baseEntities = typeof (Person).Assembly.GetTypes().Where(t => t.Namespace == typeof (Person).Namespace);
    // defines the whole hierarchy coming up from Person
    orm.TablePerClassHierarchy<Person>();
    // we map all the other classes as Table per class
    orm.TablePerClass(baseEntities.Where(t => !typeof(Person).IsAssignableFrom(t)));

    in the specific case I’ve mapped all the classes that inherit from Person using a table per class hierarchy strategy and all the other classes using a table per class strategy.
  4. The last two steps are compiling the mappings - you have to specify a list of entities you want to compile the mapping for - calling the CompileMappingFor() function exposed by the mapper object, and feed the generated mapping to NHibernate using the AddDeserializedMapping() function exposed by the configuration object:
    // compile the mapping for the specified entities
    HbmMapping mappingDocument = mapper.CompileMappingFor(baseEntities);
    // dump the mapping to the console
    Console.Write(mappingDocument.AsString());
    // inject the mapping in NHibernate
    NhConfig.AddDeserializedMapping(mappingDocument, "Domain");
  5. That’s it! you’re now ready to buildup your SessionFactory and start using it.

To dump out the mapping ConfORM generated for us, you can use a very nice extension Fabio presented in the ConfORM.UsageExamples test project (added to the this project too), here’s what we get for our domain:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="ConfORM_Tests.Domain" assembly="ConfORM_Tests" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Person">
    <id name="Id" type="Int32">
      <generator class="hilo" />
    </id>
    <discriminator />
    <property name="FirstName" />
    <property name="LastName" />
    <bag name="Pets" inverse="true" cascade="all,delete-orphan">
      <key column="Owner" on-delete="cascade" />
      <one-to-many class="Pet" />
    </bag>
    <property name="Long" />
    <property name="Guid" />
    <list name="HeldItems">
      <key column="person_key" />
      <list-index />
      <one-to-many class="Item" />
    </list>
    <many-to-one name="RightHand" />
    <many-to-one name="LeftHand" />
    <property name="BirthDate" />
  </class>
  <class name="Pet">
    <id name="Id" type="Int32">
      <generator class="hilo" />
    </id>
    <property name="Name" />
    <many-to-one name="Owner" />
  </class>
  <class name="EntityGuid">
    <id name="Id" type="Guid">
      <generator class="guid.comb" />
    </id>
    <property name="Name" />
  </class>
  <class name="EntityId">
    <id name="Id" type="Int32">
      <generator class="hilo" />
    </id>
    <property name="Name" />
  </class>
  <class name="Item">
    <id name="Id" type="Int32">
      <generator class="hilo" />
    </id>
    <property name="Name" />
  </class>
  <subclass name="Adult" extends="Person">
    <property name="Title" />
  </subclass>
  <subclass name="Child" extends="Person">
    <many-to-one name="Father" />
    <many-to-one name="Mother" />
  </subclass>
</hibernate-mapping>

Pretty cool, we’ve mapped a whole domain in more or less 8 lines of code and if we keep adding classes very few modifications have to be made; next time we’ll see how we can customize the generated mappings.

Test Project: