The official Fatica Labs Blog! RSS 2.0
# Wednesday, 25 July 2012

I just did some new project at work with heavy and extensive usage of data access over legacy databases, and I tried the DapperDotNet micro or/m instead of NHibernate. I just point before the fact that I've already all the infrastructure to map such a legacy DB in NH by using mapping by code and leveraging a lot of conventios in the DB table/field naming, so the mapping work does not make any difference for me, a part the fact that it is not needed with dapper ( or at least, not needed in the Entity based form ) since you just map the data transfer structures. So what's missing from using NH? Lets see:

  • Inheritance I was a little worried about Dapper leak of support for any kind of inheritance concept, but really I managed to do all the requirement without it, having the best dsl for querying the database did the work.
  • Identity Map We have to keep an eye to the fact the identity map does not exist anymore using a micro/orm. This not just in subsequnt queries in the same section, but when we load associations, expecially when the associated class has a lot of data. For example I had an association with an entity containing a big bounch of xml, if I load that association in a dto, I need to manage myself to load it just when the associated id changes.
  • Lazy Collections using Dapper we have to forget such automatic features, basically there is not such a concept, but I really can live without it.
  • Db Schema Create/Update I really miss that just in unit testing. You have to craft the schema by hand in your unit test. In production in my case I have no control for the schema generation *at all* so it is not a problem anyway, but I guess the NH update / generation is not enough for a real DB deployment. You probably need a DB migration in any case.
  • Linq/Hql In fact I miss LinqToNh. Not absolutely Hql. But we have to consider that a big portion of the impedence an OR/M introduces is caused to the creation of a DSL on top of plain SQL.

Let's consider the pure benefit we have from Dapper:

  • Any kind of optimized SQL is easy to submit.
  • Calling an SP handling In/out parametrs is simple as calling a query
  • Multiple resultset are easy to handle ( The Future<> in NH )
  • Bulk operations are easy too ( you still need real bulk if you realaly want to insert big amount of data )
  • Really noticeable increase in performance, due to smart ADO.NET underlayng access and to the fact we control the SQL roundtrip ourself )

So in my opinion: we probably code a little more in the data access phase, but we have more control, there is no a separate "mapping" part, that can be not so easy to mantain, but it really worth the effort to move definitely in the Micro Orm direction.

Wednesday, 25 July 2012 11:32:20 (GMT Daylight Time, UTC+01:00)  #    Comments [1] - Trackback
C# | NHibernate | ORM

# Thursday, 12 April 2012

There are scenarios in which NHibernate performance decrease even if we do all the effort to correctly use it. This could happen if we need in some circumstances to load a lot of record ( I explicitly use record instead of ‘Entity’ ) from some relational structures, and doing this the OR/M way means overload the session with a lot of entities, that is painful in term of speed. Other cases happens when we need to  write or update something that is not properly represented in the entity model we have, maybe because the model is more “read” oriented. Other cases? I’m not able to grasp all  of course, but I’m sure that you face some if you use an OR/M ( not necessarily NH ) in your daily basis. Using NHibernate an alternative could be using FlushMode=Never in session, but you still have all the OR/M plumbing in the hydrating entity code that negatively impacts the performances. I obtained impressive results in solving such a situation, by using Dapper, a so called single file OR/M. It is a single file that provider some IDbConnection extension methods, those methods works on an already opened connection, so we can use the connection sticked to the NHibernate open session, as here below:

// don't get confused by LinqToNh Query<> this one is the Dapper query
// acting on the CONNECTION :)

session.Connection.Query<MyDto>("select Name=t.Name,Mail=t.Mail from mytable t where t.Valid=@Valid",new{Valid=true});




you obtain back a big recordset of MyDto instances in almost the same time if you wire by hand a DateReader vertical on the dto, with all the error checking.

So why don’t use it always?

Because despite the name Dapper is not an OR/M, it does not keep track of modified entities, it does not help you in paginating results or lazy load the entity graph, neither helps in porting from one SQL dialect to another.

Is this strategy used somewhere else?

You probably find interesting to read this post by Sam Saffron, this solution is used in Stackoverflow.com combined with the LinqToSql OR/M to help when the OR/M performance are not enough.

By my test I experienced a performance increase of 10x in a very hacking situation, but I can’t show the case since it is not public code. Something more scientific about performance is here.

Thursday, 12 April 2012 09:41:12 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
CodeProject | Dapper | NHibernate | ORM

# Sunday, 27 November 2011

In this post Ayende talk about when we should use NHibernate and he point that in almost read only scenario other approach can be preferred. I think he forget to mention the fact that even in such a scenario we can leverage a very reliable multi DB abstraction offered by NH that can help us if we think to target different data platforms. In order to me we should say that the point of decision to choose fro NH to another approach is the ability to create an entity model, and an entity model helpful to our objectives. This can also depends on how much we are confortable with the technology. Another interesting extension of the argument is, if we should not  use NH what can we use instead ? Well not for sure EF, since the reason of renounce to NH in a project should be the same to avoid EF. The NOSql solutions works only if we can completely avoid a relational database, and the pure crude ADO.NET is just ugly. An option could be Dapper,  a lightweight OR/M ( not exactly an OR/M, but almost ) that remove all the ugliness of ADO.NET and does not change the performance in comparison on using the manual data access approach. I did not tried it myself, but one of its users is stackoverlow, so this should be by itself a guarantee.

Sunday, 27 November 2011 08:56:37 (GMT Standard Time, UTC+00:00)  #    Comments [0] - Trackback
CodeProject | NHibernate | ORM

# 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

# Sunday, 17 October 2010

 Kynetic ORM è un nuovo ORM che sfrutta le potenzialità di C# 4.0, in particolare dynamics, per consentire un utilizzo a configurazione Zero. L’autore propone un esempio completo partendo da questo modello:

 

image

E mostrando come con qualche riga di codice si realizzi di fatto l’accesso:

 

 
   1: string cn = "your connection string";
   2: var link = new KSQLLink( cn );
   3: cmd = link.From( x => x.Employees ).Where( x => x.LastName >= "C" );
   4: foreach( dynamic obj in cmd ) Console.WriteLine( "- {0}\n", obj );
 
Ci sono comunque delle facilities se si vuole creare un mapping con oggetti fortemente tipati ( ma ovviamente il codice da scrivere aumenta :-; )

Mi sembra di poter dire che sia un progetto da seguire, anche se mi sento di dire che forse incoraggia un po’ troppo l’approccio DB-First.

Sunday, 17 October 2010 09:36:22 (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
ORM

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