Try fast search NHibernate

19 July 2011

Azure Storage initialization

More than a post about “how initialize the Azure storage” this is a “bottle to sea” to check if somebody else known a best-practice, a recommendation or whatever you call it.

In the past year we had experimented the very nice and useful exception starting our Web-Role… if you have an application on Azure I’m pretty sure you saw it too:

TheNiceAzureError

Very nice and informative, even better than some of our exceptions in NHibernate.

The matter is that at some point you need the CloudStorageAccount and, at some point, you have to initialize the storage. We thought that the better place to initialize the storage is the HttpApplication.Application_Start() but… error; then we have tried the WebRole class and again… error. With no lucky I have tried to find some guideline about where initialize the storage, then I have opted for a “lazy initialization” at the first time an action with the storage is required but, again… error!!

Today I tried a new solution and hopefully it is the final-cut to the story. Here is the code:

public override bool OnStart()
{
    // For information on handling configuration changes
    // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
    RoleEnvironment.Changing += RoleEnvironmentChanging;
    WaitForRoleAvailability();

    InitializeAzureStorage();

    return base.OnStart();
}

private static void WaitForRoleAvailability()
{
    bool accountAvailable = false;
    do
    {
        try
        {
            AzureAccount.DefaultAccount();
            accountAvailable = true;
        }
        catch (RoleEnvironmentException e)
        {
            Thread.Sleep(3000);
        }
    } while (!accountAvailable);
}

And for the initialization:

InitializeAzureStorage

Today the error is away from us… but I would know if you know something better.

17 July 2011

NHibernate: playing with mapping by code (2)

galletto-alla-mediterranea
In the previous post you saw a simple example about a way to use the new mapping-by-code of NHibernate 3.2.0.
The class-by-class mapping will be, probably, the most used way just because it is very similar to the XML mapping and the “feeling of loss of control” is near to zero (the quiet of sense).
If you want experiment more adrenaline you can try ConfORM but if you like just a little bit of more adrenaline you can use the NHibernate’s ConventionModelMapper.


Inside the ConventionModelMapper

To understand what really is the ConventionModelMapper let me show you a piece of its code:
public class ConventionModelMapper : ModelMapper
{
    public ConventionModelMapper()
        : base(new SimpleModelInspector())
    {
        AppendDefaultEvents();
    }
clear! no? The ConventionModelMapper is just a specialization of a ModelMapper where, instead the ExplicitlyDeclaredModel, we are injecting another implementation of IModelInspector. To “simplify” its usage, and obscure to you the real power of Dependency-Injection, the ConventionModelMapper exposes some methods as, for instance:
public void IsPersistentProperty(Func<MemberInfo, bool, bool> match)
What are those three parameters of the delegate ?
The name of the method is the question : is it a persistent property ?
The MemberInfo is the subject of the question. The bool parameter is an “help” to take a decision and it represent what was explicitly defined (we will see later where was defined). The last bool is the answer of the question.
What happen if we have a look to the implementation of the above method ?
public void IsPersistentProperty(Func<MemberInfo, bool, bool> match)
{
    SimpleModelInspector.IsPersistentProperty(match);
}
As you can see the implementation is completely passed to the SimpleModelInspector, nothing more than an “simplification” to allow you the usage of just one class.


ConventionModelMapper vs class-by-class mapping

This is not a matter. All these ways to perform the mapping-task, in NHibernate 3.2.0, are not one versus others because you can use all together. You can organize your mapping as you feel more confortable. There will be users who prefer explicit-class-by-class for the whole mapping; there will be users who prefer the usage of ConventionModelMapper and the method-based-mapping to specify convention-exceptions/overrides; there will be users who prefer the usage of ConventionModelMapper and the class-by-class as an organization of convention-exceptions/overrides; there will be users who implements their IModelInspector based on attributes; there will be users who implements their IModelInspector based on a custom DSL.


The new mapping

Taking the domain of the previous post, and some conventions already defined there, we can start from something like this:
  1. var mapper = new ConventionModelMapper();
  2.  
  3. mapper.BeforeMapClass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
  4. mapper.BeforeMapJoinedSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
  5. mapper.BeforeMapUnionSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
  6.  
  7. mapper.BeforeMapProperty += (mi, propertyPath, map) =>
  8. {
  9.     if (typeof(decimal).Equals(propertyPath.LocalMember.GetPropertyOrFieldType()))
  10.     {
  11.         map.Type(NHibernateUtil.Currency);
  12.     }
  13. };
  14.  
  15. mapper.BeforeMapBag += (mi, propPath, map) =>
  16. {
  17.     map.Cascade(Cascade.All.Include(Cascade.DeleteOrphans));
  18.     map.BatchSize(10);
  19. };
  20.  
  21. mapper.BeforeMapClass += (mi, type, map) =>
  22.     map.Id(idmap => idmap.Generator(Generators.HighLow,
  23.         gmap => gmap.Params(new
  24.         {
  25.             table = "NextHighVaues",
  26.             column = "NextHigh",
  27.             max_lo = 100,
  28.             where = string.Format("EntityName = '{0}'", type.Name.ToLowerInvariant())
  29.         })));
  30.  
  31. Func<Type, bool, bool> matchRootEntity = (type, wasDeclared)=> typeof(Entity).Equals(type.BaseType);
  32. var entities = Assembly.GetExecutingAssembly().GetExportedTypes()
  33.     .Where(t => typeof(Entity).IsAssignableFrom(t) && !typeof(Entity).Equals(t)).ToList();
  34. mapper.IsEntity((type, wasDeclared) => entities.Contains(type));
  35. mapper.IsRootEntity(matchRootEntity);
  36. HbmMapping domainMapping = mapper.CompileMappingFor(entities);
More then the starting point (line 1), where I’m using just the constructor of ConventionModelMapper, the difference, so far, is from line 31 to 36. Because I have completely removed any kind of explicit mapping (that “incomplete class-by-class mapping”) I have to inform the ConventionModelMapper about:
  1. given a System.Type how recognize if it is an entity or not (line 32,33,34)
  2. given a System.Type how recognize if it is a root-entity (the top class of a hierarchy); line 31,35
  3. which are the classes that the ConventionModelMapper have to map (line 32, 36)
Which is the advantage ? With the mapping of the previous post each time I’m adding a class to the domain I have to add its mapping; using this new mapping I can add a class to the domain without touch the mapping.
The mapping process is not completed because in the removed class-by-class mapping there was two specifications outside our required conventions: the Customer.TaxId as natural-id and the Order.EmissionDay as Date. To specify only these two convention-exceptions I can use the method-based-mapping in this way:
mapper.Class<Customer>(map => map.NaturalId(nm => nm.Property(c => c.TaxId)));
mapper.Class<Order>(map => map.Property(o=> o.EmissionDay, pm=> pm.Type(NHibernateUtil.Date)));
You can put the two lines in any place before call mapper.CompileMappingFor(entities).


The result

The integration is pretty the same:
  1. var configuration = new Configuration();
  2. configuration.DataBaseIntegration(c =>
  3. {
  4.     c.Dialect<MsSql2008Dialect>();
  5.     c.ConnectionString = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=IntroNH;Integrated Security=True;Pooling=False";
  6.     c.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
  7.     c.SchemaAction = SchemaAutoAction.Create;
  8. });
  9. configuration.AddMapping(domainMapping);
  10. configuration.AddAuxiliaryDatabaseObject(CreateHighLowScript(Assembly.GetExecutingAssembly().GetExportedTypes().Where(t => matchRootEntity(t, false))));
The difference is just at line 10.
After build the session-factory we will have again

And the XML will be (please look it closer):
<?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="PlayWithMappingByCode"
                   assembly="PlayWithMappingByCode"
                   xmlns="urn:nhibernate-mapping-2.2">
  <class name="Customer" table="customer">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'customer'</param>
      </generator>
    </id>
    <natural-id>
      <property name="TaxId" />
    </natural-id>
    <property name="CommercialName" />
    <bag name="Orders" cascade="all,delete-orphan" batch-size="10">
      <key column="Customer" />
      <one-to-many class="Order" />
    </bag>
  </class>
  <class name="Order" table="order">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'order'</param>
      </generator>
    </id>
    <many-to-one name="Customer" />
    <property name="EmissionDay" type="Date" />
    <bag name="Items" cascade="all,delete-orphan" batch-size="10">
      <key column="Order" />
      <one-to-many class="OrderItem" />
    </bag>
  </class>
  <class name="OrderItem" table="orderitem">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'orderitem'</param>
      </generator>
    </id>
    <many-to-one name="Order" />
    <property name="Product" />
    <property name="Price" type="Currency" />
  </class>
</hibernate-mapping>
The mapping is correct and it works but just for a “casualty”…

16 July 2011

NHibernate: playing with mapping by code

GallettiAllaBraceNHibernate 3.2.0GA is going to be released and, around the NET, there are various questions about how use its “sexy-mapping”… “sexy-mapping” is not a serious definition? well… I’m bored by zero-one definitions.

I think that the “problem” is that I have explicitly avoided to call something “best practice” writing  my examples (as I done with ConfORM) and the new mapping-by-code is very flexible and you have various ways to achieve your target.
In this example I’ll try to resume the answers to various questions.

This time nobody sent me a domain so the case is not real… it is a domain just for  the exercise.



The domain

public class Entity
{
    public virtual int Id { get; set; }
}
public class Customer : Entity
{
    public virtual string CommercialName { get; set; }
    public virtual string TaxId { get; set; }
    public virtual IEnumerable<Order> Orders { get; set; }
}
public class Order : Entity
{
    public virtual Customer Customer { get; set; }
    public virtual DateTime EmissionDay { get; set; }
    public virtual IEnumerable<OrderItem> Items { get; set; }
}
public class OrderItem : Entity
{
    public virtual Order Order { get; set; }
    public virtual string Product { get; set; }
    public virtual decimal Price { get; set; }
}


The incomplete class-by-class mapping

In our mapping-process we can start from various points depending on our knowledge of NHibernate, our knowledge of the domain, how much we known our conventions, how much we really known the relations between classes and so on. For this exercise I’ll start from a very incomplete class-by-class mapping as the follow:
public class EntityMapping<T> : ClassMapping<T> where T : Entity
{
    public EntityMapping()
    {
        Id(x => x.Id);
    }
}
public class CustomerMapping : EntityMapping<Customer>
{
    public CustomerMapping()
    {
        Property(x => x.CommercialName);
        NaturalId(map => map.Property(x => x.TaxId));
        Bag(x => x.Orders, map => map.Key(km => km.Column("CustomerId")));
    }
}
public class OrderMapping : EntityMapping<Order>
{
    public OrderMapping()
    {
        ManyToOne(x => x.Customer, map => map.Column("CustomerId"));
        Property(x => x.EmissionDay, map => map.Type(NHibernateUtil.Date));
        Bag(x => x.Items, map => map.Key(km => km.Column("OrderId")));
    }
}
public class OrderItemMapping : EntityMapping<OrderItem>
{
    public OrderItemMapping()
    {
        ManyToOne(x => x.Order, map => map.Column("OrderId"));
        Property(x => x.Product);
        Property(x => x.Price);
    }
}
If you have studied the mapping-by-code you know that you can define everything using class-by-class mapping but I want show you how little is the step between explicit-mapping and conventions/defaults-mapping.


The ModelMapper

In this exercise I’ll use the ModelMapper. The ModelMapper delegates some responsibilities to others classes. You can see all classes involved analyzing all ModelMapper constructors overloads. If you have a look at the most simple constructor you will find that the ModelMapper uses, by default, the class ExplicitlyDeclaredModel. The ExplicitlyDeclaredModel does not apply any special behavior other than what was explicitly declared or NHibernate’s convetions about table/columns names and types. Using class-by-class mapping the basic usage of the ModelMapper can look as:
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());
HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
yes!, that is all… then you have to add the domainMapping to the NHibernate’s configuration instance before BuildSessionFactory.


Applying tables-naming conventions over ModelMapper

The first convention required is : “All table names are lowercase”
Any kind of convention, customization have to be declared before get all mappings so we can do something like this:
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());

mapper.BeforeMapClass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
mapper.BeforeMapJoinedSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());
mapper.BeforeMapUnionSubclass += (mi, t, map) => map.Table(t.Name.ToLowerInvariant());

HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
As you can see you can add all conventions even after add all mappings to the ModelMapper.


Applying property-types “conventions” over ModelMapper

“All properties defined as decimal have to be mapped as currency”
mapper.BeforeMapProperty += (mi, propertyPath, map) =>
{
    if (typeof(decimal).Equals(propertyPath.LocalMember.GetPropertyOrFieldType()))
    {
        map.Type(NHibernateUtil.Currency);
    }
};

 

Applying collections “conventions” over ModelMapper

“All Bags are bidirectional-one-to-many and the batch size is 10”
mapper.BeforeMapBag += (mi, propPath, map) =>
{
    map.Cascade(Cascade.All.Include(Cascade.DeleteOrphans));
    map.BatchSize(10);
};
Is that enough to accomplish the target ? No, is not. We have defined only some attributes of the collections declared as Bag but we haven’t defined which is the relation between the collection ReflectedType and the collection-item-type. We can’t define the one-to-many relation using the ModelMapper because the responsibility to define/discover all relation is delegated to the IModelInspector injected to the ModelMapper instance (note that I wrote instance). Out-of-the-box you can find some implementations of IModelInspector but if you want continue maintaining most of things under your control and you want learn the new mapping-by-code step-by-step you can simply use a class inherited from the “”default”” ExplicitlyDeclaredModel. In this case the implementation can be simply:
public class MySimpleModelInspector: ExplicitlyDeclaredModel
{
    public override bool IsOneToMany(MemberInfo member)
    {
        if(IsBag(member))
        {
            return true;
        }
        return base.IsOneToMany(member);
    }
}
and its usage is:
var modelInspector = new MySimpleModelInspector();
var mapper = new ModelMapper(modelInspector);

 

Applying POID strategy “conventions” over ModelMapper

At this point of the mapping-process we have a working an ready-to-work mapping for our above model but, where not defined, the default POID strategy is “assigned”. In this exercise I want use the HighLow strategy (aka HiLo) but not the simple version; I want use the per-entity-High-Low strategy.
Knowing how we are giving the name of the table (we wrote it just few lines above) the mapping of the convention is:
mapper.BeforeMapClass += (mi, type, map) =>
    map.Id(idmap => idmap.Generator(Generators.HighLow,
        gmap => gmap.Params(new
        {
            table = "NextHighVaues",
            column = "NextHigh",
            max_lo = 100,
            where = string.Format("EntityName = '{0}'", type.Name.ToLowerInvariant())
        })));
Is it enough ? Yes! It is… mmm… perhaps it is enough but not for me. By default NHibernate will generates a table for HighLow but will not insert all records needed by per-entity-High-Low. What we need is a smart IAuxiliaryDatabaseObject… something simple as:
private static IAuxiliaryDatabaseObject CreateHighLowScript(IModelInspector inspector, IEnumerable<Type> entities)
{
    var script = new StringBuilder(3072);
    script.AppendLine("DELETE FROM NextHighVaues;");
    script.AppendLine("ALTER TABLE NextHighVaues ADD EntityName VARCHAR(128) NOT NULL;");
    script.AppendLine("CREATE NONCLUSTERED INDEX IdxNextHighVauesEntity ON NextHighVaues (EntityName ASC);");
    script.AppendLine("GO");
    foreach (var entity in entities.Where(x => inspector.IsRootEntity(x)))
    {
        script.AppendLine(string.Format("INSERT INTO [NextHighVaues] (EntityName, NextHigh) VALUES ('{0}',1);", entity.Name.ToLowerInvariant()));
    }
    return new SimpleAuxiliaryDatabaseObject(script.ToString(), null, new HashedSet<string> { typeof(MsSql2005Dialect).FullName, typeof(MsSql2008Dialect).FullName });
}

 

Conclusions

Even if we started from a bored declarative (and incomplete) class-by-class-mapping we have changed its behavior without touch the initial mapping. The last step of the exercise is the integration with NHibernate3.2.0 and it is:
var configuration = new Configuration();
configuration.DataBaseIntegration(c =>
{
    c.Dialect<MsSql2008Dialect>();
    c.ConnectionString = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=IntroNH;Integrated Security=True;Pooling=False";
    c.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
    c.SchemaAction = SchemaAutoAction.Create;
});
configuration.AddMapping(domainMapping);
configuration.AddAuxiliaryDatabaseObject(CreateHighLowScript(modelInspector, Assembly.GetExecutingAssembly().GetExportedTypes()));

var factory = configuration.BuildSessionFactory();
// we are now ready to work with NHibernate
After build the session-factory in our db we will have:
PlatWithMappingByCode
For Tommaso guys (non crede finché non tocca)
<?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="PlayWithMappingByCode"
                   assembly="PlayWithMappingByCode"
                   xmlns="urn:nhibernate-mapping-2.2">
  <class name="Customer" table="customer">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'customer'</param>
      </generator>
    </id>
    <natural-id>
      <property name="TaxId" />
    </natural-id>
    <property name="CommercialName" />
    <bag name="Orders" cascade="all,delete-orphan" batch-size="10">
      <key column="CustomerId" />
      <one-to-many class="Order" />
    </bag>
  </class>
  <class name="Order" table="order">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'order'</param>
      </generator>
    </id>
    <many-to-one name="Customer" column="CustomerId" />
    <property name="EmissionDay" type="Date" />
    <bag name="Items" cascade="all,delete-orphan" batch-size="10">
      <key column="OrderId" />
      <one-to-many class="OrderItem" />
    </bag>
  </class>
  <class name="OrderItem" table="orderitem">
    <id name="Id" type="Int32">
      <generator class="hilo">
        <param name="table">NextHighVaues</param>
        <param name="column">NextHigh</param>
        <param name="max_lo">100</param>
        <param name="where">EntityName = 'orderitem'</param>
      </generator>
    </id>
    <many-to-one name="Order" column="OrderId" />
    <property name="Product" />
    <property name="Price" type="Currency" />
  </class>
</hibernate-mapping>

09 July 2011

Using ConfORM with modular application

I’m getting some questions about how use ConfORM in modular applications. The first commercial application mapped with ConfORM is a pretty complex modular application and if you have a look to the first ConfOrm example you can find the IModuleMapping.
Here I’ll try to explain how we have used it in that application writing a new example.

The IModuleMapper

/// <summary>
/// A template to perform a mapping using ConfOrm
/// </summary>
public interface IModuleMapper
{
    /// <summary>
    /// Register domain classes, persistent-strategies, relations and so on of a spefic module
    /// </summary>
    void DefineDomain();

    /// <summary>
    /// Register patterns of a module
    /// </summary>
    void RegisterPatterns();

    /// <summary>
    /// Customize persistence representations
    /// </summary>
    void Customize();

    /// <summary>
    /// Get all domain entities of the module.
    /// </summary>
    /// <returns>domain entities.</returns>
    IEnumerable<Type> GetEntities();
}
As you can see it is a simple template just to suggest how organize your mapping… nothing complicated.

The Domain

In the assembly Acme.ModuleA
using System;
using Acme.Domain.Common;

namespace Acme.ModuleA
{
    public class User: Entity
    {
        public string UserName { get; set; }
        public string Text { get; set; }
        public DateTime Birthday { get; set; }
    }
}
In the assembly Acme.ModuleB
using System;
using Acme.Domain.Common;
using Acme.ModuleA;

namespace Acme.ModuleB
{
    public class Article: Entity
    {
        public DateTime PublishedAt { get; set; }
        public string Title { get; set; }
        public string Text { get; set; }
        public User Author { get; set; }
    }
}

 

Some extensions

Just to not forget it later…
public static class ModuleMappingUtil
{
    public static IEnumerable<Type> MapModule(this IModuleMapper mapper)
    {
        mapper.DefineDomain();
        mapper.RegisterPatterns();
        mapper.Customize();
        return mapper.GetEntities();
    }

    public static bool IsOfModuleContaining<T>(this Type source)
    {
        return source.Assembly.Equals(typeof(T).Assembly);
    }
}

 

The mapping

You can organize the mapping of your modules in a single assembly, in general the same where you are generating the session factory, or in more than one assembly. In general you need just a little class to map a module so please don’t be exaggerated separating your application.
For this example I will show three implementations of ModuleMapper all implemented in the same assembly named Acme.Persistence.Wiring.
public class GeneralsPatternsModuleMapper : IModuleMapper
{
    private readonly Mapper mapper;
    private readonly ObjectRelationalMapper orm;

    public GeneralsPatternsModuleMapper(ObjectRelationalMapper orm, Mapper mapper)
    {
        this.orm = orm;
        this.mapper = mapper;
    }

    #region IModuleMapper Members

    public void DefineDomain()
    {
        // map .NET4 ISet<T> as a NHibernate's set
        orm.Patterns.Sets.Add(mi => mi.GetPropertyOrFieldType().GetGenericIntercafesTypeDefinitions().Contains(typeof (ISet<>)));
    }

    public void RegisterPatterns()
    {
        // all strings are length 50 characters
        mapper.PatternsAppliers.Property.Add(mi => typeof (string).Equals(mi.GetPropertyOrFieldType()), (mi, map) => map.Length(50));
      
        // when a DateTime seems to be a simple date apply NH's Date type
        mapper.PatternsAppliers.Property.Add(mi => typeof (DateTime).Equals(mi.GetPropertyOrFieldType()) && IsDate(mi.Name), (mi, map) => map.Type(NHibernateUtil.Date));

        // when a DateTime seems to not be a simple date apply NH's UtcDateTime type
        mapper.PatternsAppliers.Property.Add(mi => typeof (DateTime).Equals(mi.GetPropertyOrFieldType()) && !IsDate(mi.Name), (mi, map) => map.Type(NHibernateUtil.UtcDateTime));
    }

    public void Customize()
    {
        // Nothing to do
    }

    public IEnumerable<Type> GetEntities()
    {
        yield break;
    }

    #endregion

    public static bool IsDate(string name)
    {
        return name.EndsWith("Date") || name.StartsWith("Date") || name.EndsWith("Day") || name.EndsWith("day") || name.StartsWith("Day");
    }
}
The GeneralsPatternsModuleMapper register just part of my common convention for the current application. Then the mapping of my Acme.ModuleA:
public class ModuleAMapper : IModuleMapper
{
    private readonly Mapper mapper;
    private readonly ObjectRelationalMapper orm;

    public ModuleAMapper(ObjectRelationalMapper orm, Mapper mapper)
    {
        this.orm = orm;
        this.mapper = mapper;
    }

    public void DefineDomain()
    {
        // register all classes of my module (ConfORM will use it to discover polymorphic associations)
        orm.AddToDomain(typeof(User).Assembly.GetExportedTypes());

        // defines the persistence strategy for each root of each hierarchy
        orm.TablePerClass<User>();
    }

    public void RegisterPatterns()
    {
        // no specific patterns for this module
    }

    public void Customize()
    {
        // map a specific size (20) for a specific property of a specific class
        mapper.Class<User>(x => x.Property(user => user.UserName, map => map.Length(20)));
    }

    public IEnumerable<Type> GetEntities()
    {
        // all entities of this modules
        return typeof(User).Assembly.GetExportedTypes().Where(t=> typeof(Entity).IsAssignableFrom(t));
    }
}
The mapping of Acme.ModuleB:
public class ModuleBMapper : IModuleMapper
{
    private readonly Mapper mapper;
    private readonly ObjectRelationalMapper orm;

    public ModuleBMapper(ObjectRelationalMapper orm, Mapper mapper)
    {
        this.orm = orm;
        this.mapper = mapper;
    }

    public void DefineDomain()
    {
        // register all classes of my module (ConfORM will use it to discover polymorphic associations)
        orm.AddToDomain(typeof(Article).Assembly.GetExportedTypes());

        // defines the persistence strategy for each root of each hierarchy
        orm.TablePerClassHierarchy<Article>();
    }

    public void RegisterPatterns()
    {
        // patterns for this module

        // when a string property is named "Text" then apply StringClob type (note just for Acme.ModuleB)
        mapper.PatternsAppliers.Property.Add(
            mi => "text".Equals(mi.Name.ToLowerInvariant()) && typeof (string).Equals(mi.GetPropertyOrFieldType()) && mi.DeclaringType.IsOfModuleContaining<Article>(),
            (mi, map) => { map.Type(NHibernateUtil.StringClob); map.Length(int.MaxValue); });
    }

    public void Customize()
    {
        // nothing to do
    }

    public IEnumerable<Type> GetEntities()
    {
        // all entities of this modules
        return typeof(Article).Assembly.GetExportedTypes().Where(t => typeof(Entity).IsAssignableFrom(t));
    }
}

 

The NHibernate’s initialization

First you need a method to get all modules of your application, for simplicity here is a simple implementation:
private static IEnumerable<IModuleMapper> GetAllModulesMappers(ObjectRelationalMapper orm, Mapper mapper)
{
    yield return new GeneralsPatternsModuleMapper(orm, mapper);
    yield return new ModuleAMapper(orm, mapper);
    yield return new ModuleBMapper(orm, mapper);
}
and now you have all is needed to have the session factory:
  1. var orm = new ObjectRelationalMapper();
  2. var patternSet = new CoolPatternsAppliersHolder(orm);
  3. var mapper = new Mapper(orm, patternSet);
  4.  
  5. HbmMapping mappings = mapper.CompileMappingFor(GetAllModulesMappers(orm, mapper).SelectMany(x => x.MapModule()));
  6.  
  7. var configure = new Configuration();
  8. configure.SessionFactoryName("Demo");
  9. configure.DataBaseIntegration(db =>
  10. {
  11.     db.Dialect<MsSql2008Dialect>();
  12.     db.ConnectionStringName = "ToAcmeDb";
  13. });
  14.  
  15. configure.AddDeserializedMapping(mappings, "AcmeApplicationDomain");
  16.  
  17. ISessionFactory factory = configure.BuildSessionFactory();
In the line 5 I’m getting just one mapping document for the whole domain. You can use the method mapper.CompileMappingForEach without problems. The main matter here is the fact that I’m using just one instance of ObjectRelationalMapper and Mapper to give the whole picture of the domain of the application to ConfORM.