ConfORM: understand core pieces

6 Set

If you read the post ConfORM Gettins started you already know that NHibernate mapping task could be very easy with ConfORM. But unfortunately real project are a little bit more complicated that the example I shown in my first post about ConfORM so we need to understand how we can squeeze the tool to get the work done also when things get complicated.

The key to success is to understand which are the many configuration points of ConfORM: IDomainInspector and Mapper. This two pieces can be described as the head and the tail of the mapping process.
IDomainInspector is the entry point and also the mapping driver. This object is used to describe our domain model and currently there is only one concrete implementation of it: ObjectRelationalMapper. ObjectRelationalMapper class use ORM terminology to descride domain: TablePerClass, TablePerConcreteClass, ManyToMany, ManyToOne, OneToOne, Set, Bag, List, Poid, Component are just some of the methods you’ll find in it (they are also grouped inside the IObjectRelationalMapper interface but this is an implementation details). Another important thing to consider is that IDomainInspector is just an interface and this means that if don’t like the current implementation (ObjectRelationalMapper) you can write your own and use with ConfORM. For example you could create a DomainDrivenDesignMappper that has method like RootAggregate, ValueObjec an so on.
The other important object is the the Mapper.

namespace ConfOrm.NH
{
    public class Mapper
    {
        public Mapper(IDomainInspector domainInspector);
        public Mapper(IDomainInspector domainInspector, ICustomizersHolder customizerHolder);
        public Mapper(IDomainInspector domainInspector, IPatternsAppliersHolder patternsAppliers);

        public Mapper(IDomainInspector domainInspector, ICustomizersHolder customizerHolder,
                      IPatternsAppliersHolder patternsAppliers, ICandidatePersistentMembersProvider membersProvider);

        public IPatternsAppliersHolder PatternsAppliers { get; }

        public void Class<TRootEntity>(Action<IClassMapper<TRootEntity>> customizeAction) where TRootEntity : class;
        public void Subclass<TEntity>(Action<ISubclassMapper<TEntity>> customizeAction) where TEntity : class;

        public void JoinedSubclass<TEntity>(Action<IJoinedSubclassMapper<TEntity>> customizeAction)
            where TEntity : class;

        public void UnionSubclass<TEntity>(Action<IUnionSubclassMapper<TEntity>> customizeAction) where TEntity : class;
        public void Component<TComponent>(Action<IComponentMapper<TComponent>> customizeAction) where TComponent : class;

        public void Customize<TPersistent>(Action<IPersistentClassCustomizer<TPersistent>> customizeAction)
            where TPersistent : class;

        public void AddPoidPattern(Predicate<MemberInfo> matcher, Action<MemberInfo, IIdMapper> applier);
        public void AddPropertyPattern(Predicate<MemberInfo> matcher, Action<IPropertyMapper> applier);
        public void AddPropertyPattern(Predicate<MemberInfo> matcher, Action<MemberInfo, IPropertyMapper> applier);
        public void AddCollectionPattern(Predicate<MemberInfo> matcher, Action<ICollectionPropertiesMapper> applier);

        public void AddCollectionPattern(Predicate<MemberInfo> matcher,
                                         Action<MemberInfo, ICollectionPropertiesMapper> applier);

        public void AddManyToOnePattern(Predicate<MemberInfo> matcher, Action<IManyToOneMapper> applier);
        public void AddManyToOnePattern(Predicate<MemberInfo> matcher, Action<MemberInfo, IManyToOneMapper> applier);
        public void AddRootClassPattern(Predicate<Type> matcher, Action<Type, IClassAttributesMapper> applier);
        public void AddSubclassPattern(Predicate<Type> matcher, Action<Type, ISubclassAttributesMapper> applier);

        public void AddJoinedSubclassPattern(Predicate<Type> matcher,
                                             Action<Type, IJoinedSubclassAttributesMapper> applier);

        public void AddUnionSubclassPattern(Predicate<Type> matcher,
                                            Action<Type, IUnionSubclassAttributesMapper> applier);

        public void AddRootClassPattern(Predicate<Type> matcher, Action<IClassAttributesMapper> applier);
        public void AddSubclassPattern(Predicate<Type> matcher, Action<ISubclassAttributesMapper> applier);
        public void AddJoinedSubclassPattern(Predicate<Type> matcher, Action<IJoinedSubclassAttributesMapper> applier);
        public void AddUnionSubclassPattern(Predicate<Type> matcher, Action<IUnionSubclassAttributesMapper> applier);
        public HbmMapping CompileMappingFor(IEnumerable<Type> types);

        protected virtual Mapper.ICollectionElementRelationMapper DetermineCollectionElementRelationType(
            MemberInfo property, PropertyPath propertyPath, Type collectionElementType);

        public IEnumerable<HbmMapping> CompileMappingForEach(IEnumerable<Type> types);
        public void TypeDef<TComplex, TUserType>() where TUserType : IUserType;

        #region Nested type: ICollectionElementRelationMapper

        protected interface ICollectionElementRelationMapper
        {
            void Map(ICollectionElementRelation relation);
            void MapCollectionProperties(ICollectionPropertiesMapper mapped);
        }

        #endregion

        #region Nested type: IMapKeyRelationMapper

        protected interface IMapKeyRelationMapper
        {
            void Map(IMapKeyRelation relation);
        }

        #endregion
    }
}

If you look carefully at the namespace of this class you’ll notice the is “ConfOrm.NH” and if you analize the contructors you’ll understand that the ConfOrm.NH.Mapper class takes always an IDomainInspector and than analize and compile it to a HbmMapping instance via CompileMappingFor or CompileMappingForEach methods (read this post if you need a real sample of this usage)

With the methods on Mapper you can customize its behavior. For example you can customize the table name mapped to a class with this line of code:

mapper.Class<Answer>(cm => cm.Table("a_dummy_table_name"));

or set the Length of the properties using this expression:

mapper.Customize<Name>(name =>
{
             name.Property(np => np.First, pm => pm.Length(20));
             name.Property(np => np.Last, pm => pm.Length(35));
});

This two tasks (table names and property length) aren’t detail of the domain model. They are questions related to the database that’s the reason why the are handled by the Mapper class and not by the IDomainInspector.

Last but not least in the future someone could be interested in using ConfORM with another ORM. All you need to do is to write your own Mapper.

Are you ConfORM ?

2 Risposte to “ConfORM: understand core pieces”

  1. JustSomeJoe settembre 29, 2010 a 8:09 am #

    These introductions to ConfORM are great. Thanks for sharing and hope to see more of them. Would also be great if you provided some code downloads for others to test and work from.

    Thanks!

  2. Chorn Sokun ottobre 20, 2010 a 7:29 am #

    mapper.Customize(), could Name here be use as Component?

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: