The official Fatica Labs Blog! RSS 2.0
# Wednesday, 02 November 2011

Sometimes when we use mapping by code we want to see the generated HBM, just to understand if all is working as expected. I did this in some my old posts by dumping the hbm with an helper method, but I simply miss that the function exists as an extension method. Here below an example:

 var compiled = mapper.CompileMappingForAllExplicitlyAddedEntities();
#if DEBUG
            Trace.WriteLine(compiled.AsString());
#endif
            cfg.AddMapping(compiled);

 

We simply need to include the following using:

using NHibernate.Mapping.ByCode;

Here I use the AsString method that serialize in a string the compiled mapping.
Wednesday, 02 November 2011 14:39:29 (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
NH Mapping By Code | NHibernate

# Thursday, 20 October 2011

Since it is boring having to specify every time the Schema a table belongs to, it would be nice having a conventional strategy to automatically wire up this information. With NHibernate mapping by code functionality this is simple. The strategy I propose is having the last part of the entity namespace being equal with the schema. So for example we have an entity Product in the schema named Production we define the entity as:

MyEntities.Production.Product

Then by using a ConventionModelMapper we can write:

public class MyModelMapper:ConventionModelMapper
    {
        public MyModelMapper()
        {
            this.BeforeMapClass += (modelInspector, type, customizer) =>
                {
                    customizer.Schema(type.Namespace.Split('.').Last());
                };
        }
        
    }

And we achieve to write less line again :)

Thursday, 20 October 2011 12:05:18 (GMT Daylight Time, UTC+01:00)  #    Comments [1] - Trackback
NH Mapping By Code | NHibernate

# Friday, 09 September 2011

This post is an exercise, similar to this and this previous posts about using NHibernate  mapping by code new features present form version 3.2. The source inspiring it is an old post form Ayende, showing a non trivial requirement to map.

Here the DB model:

And the wanted object model:

So there is a lot of comments about DB refactoring needing, or on needing to have the linking entity as a visible entity in the model, but:

  • I like the idea of collapsing the linking entity.
  • I suppose that the DB is untouchable, as frequently happens.

Ayende solves the trouble by the <join/> mapping having an entity spawning two tables, so Address will be represented by joining the Table Address and PeopleAddress.

This can be done very easily in Mapping by code too, lets see how:

 

ModelMapper mapper = new ModelMapper();
            mapper.Class<Person>(m =>
                {
                    m.Id(k => k.Id,g=>g.Generator(Generators.Native));
                    m.Table("People");
                    m.Property(k => k.Name);
                    m.Bag(k => k.Addresses, t => 
                            { 
                                t.Table("PeopleAddresses");
                                t.Key(c=>c.Column("PersonId"));
                                t.Inverse(true);
                                
                            }
                         ,rel=>rel.ManyToMany(many=>many.Column("AddressId"))
                        );
                }

                );

            mapper.Class<Address>(m =>
                {
                    m.Id(k => k.Id, g => g.Generator(Generators.Native));
                    m.Table("Addresses");
                    m.Property(p => p.City);

                    m.Join("PeopleAddresses", z => 
{
z.Property(p => p.IsDefault);
z.Property(p => p.ValidFrom);
z.Property(p => p.ValidTo);
z.Key(k => k.Column("PersonId"));
});

That yield  the following mapping:

<?xml version="1.0" encoding="utf-16"?>
<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" namespace="TestMappingByCode" assembly="TestMappingByCode" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Person" table="People">
    <id name="Id" type="Int32">
      <generator class="native" />
    </id>
    <property name="Name" />
    <bag name="Addresses" table="PeopleAddresses" inverse="true">
      <key column="PersonId" />
      <many-to-many class="Address" column="AddressId" />
    </bag>
  </class>
  <class name="Address" table="Addresses">
    <id name="Id" type="Int32">
      <generator class="native" />
    </id>
    <property name="City" />
    <join table="PeopleAddresses">
      <key column="PersonId" />
      <property name="IsDefault" />
      <property name="ValidFrom" />
      <property name="ValidTo" />
    </join>
  </class>
</hibernate-mapping>

 

Exactly the ones that Ayende proposed. As you can see is pretty straightforward map even a not so common situation.

Friday, 09 September 2011 11:59:53 (GMT Daylight Time, UTC+01:00)  #    Comments [1] - Trackback
NH Mapping By Code | NHibernate | ORM

# Friday, 02 September 2011

In this post we done some effort in automatically generate the mapping based on convention, but we miss a very common one: table names is usually the pluralized entity name. This is usually done by using an inflector. Thanks to Stack Overflow, I found this question about it, and choose that one, that is a single easily embeddable file. So we modify a little our AutoMapper class as below:

void AutoMapper_BeforeMapClass(IModelInspector modelInspector, Type type, IClassAttributesMapper classCustomizer)
       {
           //
           // Create the column name as "c"+EntityName+"Id"
           //
           classCustomizer.Id(k => 
                               { 
                                   k.Generator(Generators.Native); k.Column("c" + type.Name + "Id"); 
                               }
                               );
           classCustomizer.Table(Inflector.Pluralize(type.Name));
        }

 

And this is all, the generated mapping will change as:

<hibernate-mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:x=""
sd="http://www.w3.org/2001/XMLSchema" namespace="MappingByCode" assembly="Mappin
gByCode" xmlns="urn:nhibernate-mapping-2.2">
  <class name="SimpleEntity" table="SimpleEntities">
    <id name="Id" column="cSimpleEntityId" type="Int32">
      <generator class="native" />
    </id>
    <property name="Description">
      <column name="txtSimpleEntityDescr" sql-type="AnsiString" />
    </property>
    <many-to-one name="Referred" column="cReferredId" />
  </class>

Just for better sharing, I published this “laboratory” project here.

Friday, 02 September 2011 14:42:10 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
NH Mapping By Code | NHibernate | ORM

# Thursday, 01 September 2011

Since version 3.2.0 NHibernate  has an embedded strategy for mapping by code, that basically comes from Fabio Maulo’s ConfORM. With some reading at this Fabio post,  this other one, and this one too, I wrote my own sample just to see what we can do.

Even if we can use mapping by code to map class by class the entire model, something more interesting can be done by writing some convention-based automatic mapper, that can help us even when we face legacy ( non code first ) databases with some (perverted) naming convention.

We have to consider first the ModelMapper class, this class in the NH mapping by code is the one responsible for driving the mapping generator. It provides a suite of events to intercept the actual generation of each elements in the mapping. By listening these event we can decorate the detail of the single element, for example the Id generator class, the SqlType, the column name, and so on. ModelMapper uses a ModelInspector to get the way we want to map each portion of the entity ( properties, many-to-one, collections ), or if we have a component, or a subclass and so on. We realize our AutoMapper class by deriving a ModelMapper and internally subscribing some events, and passing to it a custom ModelInspector ( we named it AutoModelInspector ).

Let’s start with a very basic model:

ultra simple model

Basically an entity that unidirectionally associates with a referred one. Let’s say we have these example database conventions:

  • Identifier column are named “c”+EntityName+”Id” and are autoincrement
  • Column description are named “txt”+EntityName+”Descr”
  • Column of type string have to be prefixed with “txt”
  • Column of type string have to be AnsiString ( for DDL generation of CHAR instead of NChar )
  • Foreign key column have to be called “c”+ForeignEntityName+”Id”

So let’s see how we wrote the custom model mapper:

class AutoMapper:ModelMapper
    {
        public AutoMapper()
            : base(new AutoModelInspector())
        {
            //subscribe required ebvents for this simple strategy ...
            this.BeforeMapClass += new RootClassMappingHandler(AutoMapper_BeforeMapClass);
            this.BeforeMapProperty += new PropertyMappingHandler(AutoMapper_BeforeMapProperty);
            this.BeforeMapManyToOne += new ManyToOneMappingHandler(AutoMapper_BeforeMapManyToOne);
            //...
            //other events....
        }
        
        void AutoMapper_BeforeMapManyToOne(IModelInspector modelInspector, PropertyPath member, IManyToOneMapper propertyCustomizer)
        {
            //
            // name the column for many to one as
            // "c"+foreignEntityName+"id"
            //
            var pi = member.LocalMember as PropertyInfo;
            if (null != pi)
            {
                propertyCustomizer.Column(k => k.Name("c"+pi.PropertyType.Name+"Id"));
            }
        }

        void AutoMapper_BeforeMapProperty(IModelInspector modelInspector, PropertyPath member, IPropertyMapper propertyCustomizer)
        {
            //
            // Treat description as a special case: "txt"+EntityName+"Descr"
            // but for all property of type string prefix with "txt"
            //
            if (member.LocalMember.Name == "Description")
            {
                propertyCustomizer.Column(k =>
                    {
                        k.Name("txt" + member.GetContainerEntity(modelInspector).Name + "Descr");
                        k.SqlType("AnsiString");
                    }
                    );
            }
            else
            {
                var pi = member.LocalMember as PropertyInfo;
                
                if (null != pi && pi.PropertyType == typeof(string))
                {
                    propertyCustomizer.Column(k =>
                    {
                        k.Name("txt" + member.LocalMember.Name);
                        k.SqlType("AnsiString");
                    }
                   );
                }
            }
        }
       
        void AutoMapper_BeforeMapClass(IModelInspector modelInspector, Type type, IClassAttributesMapper classCustomizer)
        {
            //
            // Create the column name as "c"+EntityName+"Id"
            //
            classCustomizer.Id(k => { k.Generator(Generators.Native); k.Column("c" + type.Name + "Id"); });
        }

        
    }

 

The event handlers apply the convention we said before. As we see we pass a special model inspector in the constructor, that is implemented as below:

class AutoModelInspector:IModelInspector
    {
        #region IModelInspector Members

       
        public IEnumerable<string> GetPropertiesSplits(Type type)
        {
            return new string[0];
        }

        public bool IsAny(System.Reflection.MemberInfo member)
        {
            return false;
        }

        
        public bool IsComponent(Type type)
        {
            return false;
        }

       
        public bool IsEntity(Type type)
        {
            return true;
        }

       
        
        public bool IsManyToOne(System.Reflection.MemberInfo member)
        {
            //property referring other entity is considered many-to-ones...
            var pi = member as PropertyInfo;
            if (null != pi)
            {
                return pi.PropertyType.FullName.IndexOf("MappingByCode") != -1;
            }
            return false;
        }

        public bool IsMemberOfComposedId(System.Reflection.MemberInfo member)
        {
            return false;
        }

        public bool IsMemberOfNaturalId(System.Reflection.MemberInfo member)
        {
            return false;
        }

      
        public bool IsPersistentId(System.Reflection.MemberInfo member)
        {
            return member.Name == "Id";
        }

        public bool IsPersistentProperty(System.Reflection.MemberInfo member)
        {
            return member.Name != "Id";
        }

        public bool IsProperty(System.Reflection.MemberInfo member)
        {
            if (member.Name != "Id") // property named id have to be mapped as keys...
            {
                var pi = member as PropertyInfo;
                if (null != pi)
                {
                    // just simple stading that if a property is an entity we have 
                    // a many-to-one relation type, so property is false
                    if (pi.PropertyType.FullName.IndexOf("MappingByCode") == -1)
                        return true;
                }

            }
            return false;
                
        }

        public bool IsRootEntity(Type type)
        {
            return type.BaseType == typeof(object);
        }

       
        
        public bool IsTablePerClassSplit(Type type, object splitGroupId, System.Reflection.MemberInfo member)
        {
            return false;
        }

       
        public bool IsVersion(System.Reflection.MemberInfo member)
        {
            return false;
        }

        #endregion
    }

 

As we say there is a bounch of IsXXXXX function, that are called for each portion of the class in order to know what to do with it. Our implementation is absolutely incomplete ( not implemented function omitted ), but it feet the simple requirement we stated. Then we can see how we actually realize the mapping:

static void Main(string[] args)
       {
           AutoMapper mapper = new AutoMapper();
          
           //this line simple rely on the fact
           //all and just the entities are exported...
           var map = mapper.CompileMappingFor(Assembly.GetExecutingAssembly().GetExportedTypes());

           //dump the mapping on the console
           XmlSerializer ser = new XmlSerializer(map.GetType());
           ser.Serialize(Console.Out, map);
       }

Simple, isn’t ?

The resulting map, as dumped on the console is:

image

That fulfill the actually simple requirements. So is just a matter of recognize the convention and the exceptions, and let’s go auto-mapping!

Thursday, 01 September 2011 14:58:04 (GMT Daylight Time, UTC+01:00)  #    Comments [2] - Trackback
NHibernate | ORM | NH Mapping By Code

My Stack Overflow
Contacts

Send mail to the author(s) E-mail

Tags
profile for Felice Pollano at Stack Overflow, Q&A for professional and enthusiast programmers
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2017
Felice Pollano
Sign In
Statistics
Total Posts: 157
This Year: 0
This Month: 0
This Week: 0
Comments: 124
This blog visits
All Content © 2017, Felice Pollano
DasBlog theme 'Business' created by Christoph De Baene (delarou) and modified by Felice Pollano