Tag Archives: .NET

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 ?

ConfORM- Getting started

2 Set

ConfORM is a just another option to create the mapping for NHibernate. Out-of-the-box NHibernate mapping’s can be created only with XML mapping files (*.hbb.xml files). ConfORM uses code instead of XML. If you are thinking that there is already at least one tool that follow this approach you should read this post to understand which are the differences between the other tools and ConfORM.
After this brief introduction I want to show you a little example of ConfORM’s usage to demonstrate how easy could be life with this tool.  
Here below I posted a screenshot of my domain model. As you can see there is nothing special here: some Collections and some ManyToOne relationships. There is also a read-only property: Element.HasGroupedAnswer (sorry you can’t see it in the screenshot below) .

image

The very first step is to create a valid configuration object for NHibernate. Using NHibernate.Cfg.Loquacious feature from NHibernate version 3 this can be done with this lines of code.

            Configuration configure = new Configuration();
            configure.SessionFactoryName("Demo");
            configure.Proxy(p =>
            {
                p.Validation = false;
                p.ProxyFactoryFactory<ProxyFactoryFactory>();
            });
            configure.Properties["current_session_context_class"] = _context;
            configure.DataBaseIntegration(db =>
            {
                db.Dialect<MsSql2008Dialect>();
                db.Driver<SqlClientDriver>();
                db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
                db.IsolationLevel = IsolationLevel.ReadCommitted;
                db.LogFormatedSql = LogSqlInConsole;
                db.LogSqlInConsole = LogSqlInConsole;                
                db.ConnectionString = "yuor connection string goes here";
                db.Timeout = 10;
                db.HqlToSqlSubstitutions = "true 1, false 0, yes 'Y', no 'N'";
            });
 

Once configuration object is ready we must setup mapping for our domain. Now it’s time to use ConfORM. I decided to wrap all mapping stuff inside the class shown below.

    public class ConfOrmDomainMapper
    {
        public ConfOrmDomainMapper()
        {
            orm = new ObjectRelationalMapper();         
            orm.Patterns.PoidStrategies.Add(new NativePoidPattern());
            var patternsAppliers = new CoolPatternsAppliersHolder(orm);

            mapper = new Mapper(orm, patternsAppliers);

            DefineDomain();
            DefineMapping();
        }

        private void DefineMapping()
        {           
        }

        private void DefineDomain()
        {
            orm.TablePerClass(GetTypes());
        }

        public HbmMapping Mapping
        {
            get { return mapper.CompileMappingFor(GetTypes()); }
        }

        IEnumerable<Type> GetTypes()
        {
            var type = typeof(BaseEntity);
            return type.Assembly.GetTypes().Where(t => t.BaseType == type);
        }
        private readonly ObjectRelationalMapper orm;
        private readonly Mapper mapper;
    }

Since all the classes in my domain model inherit from a common class called BaseEntity I can use reflection to get all types with a single line of code. This is not mandatory for ConfORM but as you can the result is very nice. In this simple sample I don’t need to customize the mapper but if you need to do you can use the Mapper class instance. Now all the mapping is already done. Since I used CoolPatternsAppliersHolder ConfORM already create a complete mapping to start working with NHibernate (I’ll blog some details about it in the future)

To finish I need to join ConfORM mappings and NHibernate configuration. This task is done with this few lines of code:

ConfOrmDomainMapper domainMapper = new ConfOrmDomainMapper();
configure.AddDeserializedMapping(domainMapper.Mapping, "MyAppDomain");

After this I’m ready to create a SessionFactory with

configure.BuildSessionFactory();

and start using NHibernate a usual.

This was just the beginning. I hope to find some more time to write again about ConfORM.

I want also thank Fabio Maulo for sharing with community this another piece of great code!

IronRuby

26 Lug

Today I watched this realy interesting presentation about IronRuby. Now that the implementation is near the version 0.9 I believe it’s time to start using IronRuby in a production environment. First of all I’ll use it for testing (RSpec) and for developing web application (Rails and IronRubyMVC)

If you have time don’t miss it!

Iron Ruby (Ben Hall) from Vista Squad on Vimeo.