Lesser-Known NHibernate Features: Custom Loggers

Extensible as it is, it’s no wonder that NHibernate also supports injecting custom loggers. The support is twofold:

  • There’s the ILoggerFactory interface, that must be implemented by custom logger factories; this is the responsible for creating actual loggers;
  • Then there’s the IInternalLogger interface, the one that provides the common functions found in most loggers (warn, info, debug, error, fatal, etc).

By default, it uses Log4Net, but it is easy to add our own logger.

So, let’s start by implementing a logger factory – just the skeleton, I leave it to you as an exercise:

public class CustomLoggerFactory : ILoggerFactory

{

    public IInternalLogger LoggerFor(Type type)

    {

        return new CustomLogger(type.FullName);

    }

 

    public IInternalLogger LoggerFor(String keyName)

    {

        return new CustomLogger(keyName);

    }

}

And then the actual logger:

public class CustomLogger : IInternalLogger

{

    public String Key { get; private set; }

 

    public CustomLogger(String key)

    {

        this.Key = key;

    }

 

    public void Debug(Object message, Exception exception)

    {

    }

 

    public void Debug(Object message)

    {

    }

 

    public void DebugFormat(String format, params Object[] args)

    {

    }

 

    public void Error(Object message, Exception exception)

    {

    }

 

    public void Error(Object message)

    {

    }

 

    public void ErrorFormat(String format, params Object[] args)

    {

    }

 

    public void Fatal(Object message, Exception exception)

    {

    }

 

    public void Fatal(Object message)

    {

    }

 

    public void Info(Object message, Exception exception)

    {

    }

 

    public void Info(Object message)

    {

    }

 

    public void InfoFormat(String format, params Object[] args)

    {

    }

 

    public Boolean IsDebugEnabled

    {

        get { return true; }

    }

 

    public Boolean IsErrorEnabled

    {

        get { return true; }

    }

 

    public Boolean IsFatalEnabled

    {

        get { return true; }

    }

 

    public Boolean IsInfoEnabled

    {

        get { return true; }

    }

 

    public Boolean IsWarnEnabled

    {

        get { return true; }

    }

 

    public void Warn(Object message, Exception exception)

    {

    }

 

    public void Warn(Object message)

    {

    }

 

    public void WarnFormat(String format, params Object[] args)

    {

    }

}

Remember, this is just a skeleton, do implement these methods anyway you like.

Now, all that is left is the registration:

LoggerProvider.SetLoggersFactory(new CustomLoggerFactory());

And NHibernate will start logging using your logger!

PS – Issue NH-3776 is an attempt to make using logger factories even simpler and in a similar fashion to other pluggable features.

Lesser-Known NHibernate Features: Mapping By Attributes

Some O/RMs do their mapping based on attributes. LINQ to SQL and Entity Framework are good examples, although Entity Framework also supports mapping by code. I’m not saying this is good or bad – some people think it “pollutes” POCOs, other think it makes them easier to understand -, but, likewise, NHibernate also allows to map entities by attributes, let’s see how.

First, add a reference to the NHibernate.Mapping.Attributes NuGet package:

image

Next, go to your entity and start adding some attributes:

[NHibernate.Mapping.Attributes.Class(Table = "blog", Lazy = true)]

public class Blog

{

    public Blog()

    {

        this.Posts = new List<Post>();

    }


    [NHibernate.Mapping.Attributes.Id(0, Column = "blog_id", Name = "BlogId")]

    [NHibernate.Mapping.Attributes.Generator(1, Class = "hilo")]

    public virtual Int32 BlogId { get; set; }


    [NHibernate.Mapping.Attributes.Property(Name = "Picture", Column = "picture", NotNull = false, TypeType = typeof(ImageUserType), Lazy = true)]

    public virtual Image Picture { get; set; }


    [NHibernate.Mapping.Attributes.Property(Name = "PostCount", Formula = "(SELECT COUNT(1) FROM post WHERE post.blog_id = blog_id)")]

    public virtual Int64 PostCount { get; protected set; }


    [NHibernate.Mapping.Attributes.ManyToOne(0, Column = "user_id", NotNull = true, Lazy = NHibernate.Mapping.Attributes.Laziness.NoProxy, Name = "Owner", Cascade = "save-update")]

    [NHibernate.Mapping.Attributes.Key(1)]

    public virtual User Owner { get; set; }


    [NHibernate.Mapping.Attributes.Property(Name = "Name", Column = "name", NotNull = true, Length = 50)]

    public virtual String Name { get; set; }


    [NHibernate.Mapping.Attributes.Property(Name = "Creation", Column = "creation", NotNull = true)]

    public virtual DateTime Creation { get; set; }


    [NHibernate.Mapping.Attributes.List(0, Name = "Posts", Cascade = "all-delete-orphan", Lazy = NHibernate.Mapping.Attributes.CollectionLazy.True, Inverse = true, Generic = true)]

    [NHibernate.Mapping.Attributes.Key(1, Column = "blog_id", NotNull = true)]

    [NHibernate.Mapping.Attributes.Index(2, Column = "number")]

    [NHibernate.Mapping.Attributes.OneToMany(3, ClassType = typeof(Post))]

    public virtual IList<Post> Posts { get; protected set; }

}

Basically, you will use:

  • ClassAttribute for marking a class as an entity;
  • IdAttribute: for declaring the id property;
  • GeneratorAttribute: for the id generator strategy;
  • PropertyAttribute: a mapped property;
  • BagAttribute/ListAttribute/SetAttribute/ArrayAttribute/etc: kinds of collections;
  • KeyAttribute: the key in a relation;
  • ElementAttribute: an element of an indexed collection;
  • IndexAttribute: the index in an indexed collection;
  • OneToManyAttribute/ManyToOneAttribute/OneToOneAttribute/ManyToManyAttribute: an endpoint property.

All these attributes live in the NHibernate.Mapping.Attributes namespace and are named very closely to the equivalent HBM.XML elements, which means they must be ordered (notice the first number on some attributes). Now, in order to actually make sense of these attributes, you need to:

var cfg = new Configuration();

var serializer = new HbmSerializer() { Validate = true };


using (var stream = serializer.Serialize(assemblyContainingEntitiesWithAttributes))

{

    cfg.AddInputStream(stream);

}

And that’s all it takes! Have fun! Winking smile

Lesser-Known NHibernate Features: Versioning and Optimistic Concurrency

NHibernate supports the notion of entity version. An entity version is the value of some entity property that is mapped as versioned. There are several strategies for versioning:

  • A numeric counter;
  • The current (UTC) timestamp;
  • The database timestamp;
  • The system elapsed ticks (DateTime.Ticks);
  • A database-specific row version (ROWVERSION in SQL Server, ORA_ROWSCN in Oracle, etc).

 

We map a version property as this:

public class VersionedEntity

{

    public int Id { get; protected set; }

    public int Version { get; protected set; }

}


public class VersionedEntityClassMapping<VersionedEntity>

{

    public VersionedEntityClassMapping()

    {

        this.Id(x => x.Id, x => x.Generator(Generators.Identity));

        this.Version(x => x.Version, x => x.Type(NHibernateUtil.Int32));

        //etc

    }

}

If you wish to use a strategy other than auto-incrementing versioning, just replace NHibernateUtil.Int32 by another instance of a class implementing IVersionType, such as NHibernateUtil.Ticks, NHibernateUtil.Timestamp, NHibernateUtil.UtcDateTime, NHibernateUtil.DbTimestamp, NHibernateUtil.Binary (for SQL Server), or a similar one – or roll out your own strategy.

Close to the notion of versioning comes optimistic concurrency. Using optimistic concurrency control, when a record is about to be updated, it is checked against a pre-saved value or set of values (the version), together with its primary key. If it doesn’t match, the number of affected records will be 0 instead of 1, and we know something went wrong: because the primary key doesn’t change, then it has to be the version:

UPDATE some_table

SET some_column = @p1

WHERE id = @p2

AND version = @p3

Optimistic concurrency can use:

  • The version property (if any);
  • All of the entity’s properties;
  • All the dirty properties.

We just need to tell NHibernate which strategy we want to use:

public class VersionedEntityClassMapping<VersionedEntity>

{

    public VersionedEntityClassMapping()

    {

        this.Id(x => x.Id, x => x.Generator(Generators.Identity));

        this.Version(x => x.Version, x => x.Type(NHibernateUtil.Int32));

        this.OptimisticLock(OptimisticLockMode.Version);//NHibernate 4.0, no need to specify since this is the default

        //etc

    }

}

And that’s it. Happy versioning!

Lesser-Known NHibernate Features: Filtering an Unloaded Collection

Suppose you have an entity with a collection of other entities (one to many, many to many); this collection is normally represented by some property implementing IEnumerable<T>, or one some more specific interface.

If we want to query this collection, we normally have to load all of its items. For indexed collections, it is possible to use extra-lazy laziness, which means NHibernate will only load one item at a time, instead of all at once, but this might even be worse, because it would result in multiple SELECT statements.

NHibernate offers a nice mechanism to filter and order a collection without actually loading all of its items; it’s the CreateFilter method of the ISession, and we use it like this:

   1: //get an order

   2: var order = session.Query<Order>().First();

   3:  

   4: //all order details of this order where quantity is greater than one

   5: var detailsWithMoreThanOneItem = session.CreateFilter(order.Details, "WHERE Quantity > 1").List<OrderDetail>();

   6:  

   7: //all order details of this order sorted by their quantity in descending order

   8: var detailsSortedByQuantityInDescendingOrder = session.CreateFilter(o.Details, "ORDER BY Quantity DESC").List<OrderDetail>();

I even once wrote a helper method for querying collections with LINQ without actually loading them; its usage is:

   1: //all order details of this order where quantity is greater than one

   2: var detailsWithMoreThanOneItem = order.Details.Query().Where(d => d.Quantity > 1).ToList();

The Query extension method will check to see if the collection has already been loaded, in which case, it resorts to LINQ to Objects, otherwise, it generates a proper LINQ query. You can find the source code here.

Lesser-Known NHibernate Features: Result Transformers

A result transformer, in NHibernate, is some class that implements the IResultTransformer interface:

   1: public interface IResultTransformer

   2: {

   3:     IList TransformList(IList collection);

   4:     Object TransformTuple(Object[] tuple, String[] aliases);

   5: }

Most query APIs, except LINQ, support specifying a result transformer. So, what is a result transformer used for? Just what the name says: it turns the values obtained from a query into some object. Normally, we just let NHibernate transform these values into instances of our entities, but we may want to do something different, either because we haven’t mapped some class that we want to use, or because we are not returning all of the entity’s properties, etc.

NHibernate includes some result transformers:

  • AliasToBeanResultTransformer: allows to transform a result to a user specified class which will be populated via setter methods or fields matching the alias names;
  • AliasToBeanConstructorResultTransformer: identical to AliasToBeanResultTransformer, but we specify a constructor for creating new instances of the target class;
  • AliasToEntityMapResultTransformer: returns a dictionary where the keys are the aliases and the values the corresponding columns;
  • AliasedTupleSubsetResultTransformer: ignores a tuple element if its corresponding alias is null;
  • CacheableResultTransformer: used to transform tuples to a value(s) that can be cached;
  • DistinctRootEntityResultTransformer: for joined queries, returns distinct root entities only;
  • PassThroughResultTransformer: just returns the row as it was obtained from the database;
  • RootEntityResultTransformer; returns the root entity of a joined query;
  • ToListResultTransformer: transforms each result row from a tuple into a IList, such that what you end up with is a IList of ILists.

All of these can be obtained from static properties in class NHibernate.Transform.Transformers. NHibernate implicitly uses some of these, for example, LINQ queries always use DistinctRootEntityResultTransformer.

It is easy to build our own transformer. Have a look at the following example:

   1: public class ExpressionsResultTransformer : IResultTransformer

   2: {

   3:     private readonly Type type;

   4:     private readonly Func<Object> constructorFunc;

   5:     private readonly ConstructorInfo constructor;

   6:     private readonly Object[] parameters;

   7:     private readonly Dictionary<Int32, String> expressions = new Dictionary<Int32, String>();

   8:     private PropertyDescriptorCollection props;

   9:  

  10:     public ExpressionsResultTransformer(ConstructorInfo constructor, params Object[] parameters)

  11:     {

  12:         this.constructor = constructor;

  13:         this.parameters = parameters;

  14:     }

  15:  

  16:     public ExpressionsResultTransformer(Func<Object> constructorFunc)

  17:     {

  18:         this.constructorFunc = constructorFunc;

  19:     }

  20:  

  21:     public ExpressionsResultTransformer(Type type)

  22:     {

  23:         this.type = type;

  24:     }

  25:  

  26:     private Object CreateInstance()

  27:     {

  28:         if (this.type != null)

  29:         {

  30:             return (Activator.CreateInstance(this.type));

  31:         }

  32:         else if (this.constructorFunc != null)

  33:         {

  34:             return (this.constructorFunc());

  35:         }

  36:         else

  37:         {

  38:             return (this.constructor.Invoke(this.parameters));

  39:         }

  40:     }

  41:  

  42:     public ExpressionsResultTransformer Add(Int32 index, String property)

  43:     {

  44:         this.expressions[index] = property;

  45:         return (this);

  46:     }

  47:  

  48:     public ExpressionsResultTransformer Add(params String[] properties)

  49:     {

  50:         foreach (var property in properties)

  51:         {

  52:             this.Add(property);

  53:         }

  54:  

  55:         return (this);

  56:     }

  57:  

  58:     public ExpressionsResultTransformer Add(String property)

  59:     {

  60:         var max = this.expressions.Keys.DefaultIfEmpty(-1).Max();

  61:         return (this.Add(max + 1, property));

  62:     }

  63:  

  64:     public static ExpressionsResultTransformer Add<T>(params String[] properties) where T : new()

  65:     {

  66:         return (new ExpressionsResultTransformer<T>().Add(properties));

  67:     }

  68:  

  69:     #region IResultTransformer Members

  70:  

  71:     IList IResultTransformer.TransformList(IList collection)

  72:     {

  73:         return (collection);

  74:     }

  75:  

  76:     Object IResultTransformer.TransformTuple(Object[] tuple, String[] aliases)

  77:     {

  78:         var entity = this.CreateInstance();

  79:  

  80:         if (this.props == null)

  81:         {

  82:             this.props = TypeDescriptor.GetProperties(entity);

  83:         }

  84:  

  85:         foreach (var expression in this.expressions)

  86:         {

  87:             this.props[expression.Value].SetValue(entity, tuple[expression.Key]);

  88:         }

  89:  

  90:         return (entity);

  91:     }

  92:  

  93:     #endregion

  94: }

  95:  

  96: public sealed class ExpressionsResultTransformer<T> : ExpressionsResultTransformer where T : new()

  97: {

  98:     public ExpressionsResultTransformer() : base(typeof(T))

  99:     {

 100:     }

 101:  

 102:     public ExpressionsResultTransformer(Func<T> constructor) : base(new Func<Object>(() => (Object) constructor()))

 103:     {

 104:     }

 105:  

 106:     public ExpressionsResultTransformer(ConstructorInfo constructor, params Object[] parameters) : base(constructor, parameters)

 107:     {

 108:     }

 109: }

The TransformTuple method is the one used to turn each returned record into an instance of something. TransformList is called at the end, when all the records have been processed.

The ExpressionResultTransformer class allows us to select which indexes, in the database record, map to which properties in some entity. For our convenience, it offers a number of options to construct an instance (type, constructor + parameters and delegate). We would use it like this:

   1: var products = session.CreateSQLQuery("select p.Name, p.Price, p.ProductId from Product p").SetResultTransformer(ExpressionsResultTransformer.Add<Product>("Name", "Price", "ProductId")).List<Product>();

Getting the SQL for HQL and Criteria Queries

OK, so, I already showed how we can get the SQL that was generated from a LINQ query. Of course, we can do the same for both HQL and Criteria APIs as well (QueryOver is just a wrapper around Criteria, mind you).

So, for HQL (and SQL), it goes like this:

   1: public static class QueryExtensions

   2: {

   3:     private static readonly PropertyInfo sessionProperty = typeof (QueryImpl).GetProperty("Session", BindingFlags.NonPublic | BindingFlags.Instance);

   4:  

   5:     public static String ToSql(this IQuery query)

   6:     {

   7:         if (query is QueryImpl)

   8:         {

   9:             var session = sessionProperty.GetValue(query, null) as ISession;

  10:             var sessionImpl = session.GetSessionImplementation();

  11:             var translatorFactory = new ASTQueryTranslatorFactory();

  12:             var translators = translatorFactory.CreateQueryTranslators(query.QueryString, null, false, sessionImpl.EnabledFilters, sessionImpl.Factory);

  13:  

  14:             return translators[0].SQLString;

  15:         }

  16:         else if (query is SqlQueryImpl)

  17:         {

  18:             return (query.QueryString);

  19:         }

  20:  

  21:         throw (new NotSupportedException("Query type is not supported."));

  22:     }

  23: }

You can pass any implementation if IQuery, such as one produced from ISession.CreateQuery() or ISession.CreateSQLQuery(). The static field is merely for performance reasons.

As for Criteria:

   1: public static class CriteriaExtensions

   2: {

   3:     public static String ToSql(this ICriteria criteria)

   4:     {

   5:         var criteriaImpl = criteria as CriteriaImpl;

   6:         var sessionImpl = criteriaImpl.Session;

   7:         var factory = sessionImpl.Factory;

   8:         var implementors = factory.GetImplementors(criteriaImpl.EntityOrClassName);

   9:         var loader = new CriteriaLoader(factory.GetEntityPersister(implementors[0]) as IOuterJoinLoadable, factory, criteriaImpl, implementors[0], sessionImpl.EnabledFilters);

  10:  

  11:         return loader.SqlString.ToString();

  12:     }

  13: }

And finally, QueryOver, just a small wrapper around the Criteria version:

   1: public static class QueryOverExtensions

   2: {

   3:     public static String ToSql(this IQueryOver queryOver)

   4:     {

   5:         var criteria = queryOver.UnderlyingCriteria;

   6:         return (criteria.ToSql());

   7:     }

   8: }

Hope you find this useful! Winking smile

Adding Support for ISupportInitialize in NHibernate

The .NET ISupportInitialize interface is used when we want to support staged initialization for objects. Its BeginInit method is called when initialization is about to start and EndInit when it is finished.

If we want, it is easy to add support for it in NHibernate. An option would be:

  • BeginInit is called when the object is instantiated, like when NHibernate has loaded a record from the database and is about to hydrate the entity, and immediately after the Id property is set;
  • EndInit is called after all properties are set.

We do this by using a custom interceptor, like we have in the past. We start by writing a class that inherits from EmptyInterceptor, and implements the listener interface for the PostLoad event, IPostLoadEventListener:

   1: public sealed class SupportInitializeInterceptor : EmptyInterceptor, IPostLoadEventListener

   2: {

   3:     private ISession session = null;

   4:  

   5:     public override void SetSession(ISession session)

   6:     {

   7:         this.session = session;

   8:         base.SetSession(session);

   9:     }

  10:  

  11:     public override Object Instantiate(String clazz, EntityMode entityMode, Object id)

  12:     {

  13:         var listeners = (this.session.SessionFactory as SessionFactoryImpl).EventListeners;

  14:         var metadata = this.session.SessionFactory.GetClassMetadata(clazz);

  15:         var proxy = metadata.Instantiate(id, entityMode);

  16:         var initializable = proxy as ISupportInitialize;

  17:  

  18:         if (initializable != null)

  19:         {

  20:             initializable.BeginInit();

  21:         }

  22:  

  23:         if (listeners.PostLoadEventListeners.OfType<SupportInitializeInterceptor>().Any() == false)

  24:         {

  25:             listeners.PostLoadEventListeners = listeners.PostLoadEventListeners.Concat(new IPostLoadEventListener[] { this }).ToArray();

  26:         }

  27:  

  28:         return (proxy);

  29:     }

  30:  

  31:     #region IPostLoadEventListener Members

  32:  

  33:     void IPostLoadEventListener.OnPostLoad(PostLoadEvent @event)

  34:     {

  35:         var initializable = @event.Entity as ISupportInitialize;

  36:  

  37:         if (initializable != null)

  38:         {

  39:             initializable.EndInit();

  40:         }

  41:     }

  42:  

  43:     #endregion

  44: }

Then, before creating a session factory, we need to register it in the Configuration instance:

   1: var sessionFactory = cfg.SetInterceptor(new SupportInitializeInterceptor()).BuildSessionFactory();

Now, if your entity implements ISupportInitialize, NHibernate will automagically call its methods at the proper time. As simple as this! Winking smile

Lesser-Known NHibernate Features – Generating Database Scripts

As you may know, NHibernate knows how to generate the database for you from its model. Any of the supported databases will do.

What you may not know is that you can simply generate the SQL scripts that would be used to either generate the database from scratch or just update it to match the model as it is. For that you use the SchemaExport and SchemaValidator classes.

SchemaValidator takes a Configuration instance and basically throws an exception if, when its Validate method is called, the database does not match the model.

SchemaExport has far more options; it can:

  • Create or drop a database model based on the entity model;
  • Output the SQL to a file, either executing it at the same time or not;
  • Execute the SQL to another arbitrary database connection;
  • Execute a custom action after each line of the generated SQL script.

An example:

   1: var validator = new SchemaValidator(cfg);

   2:  

   3: try

   4: {

   5:     validator.Validate();

   6: }

   7: catch

   8: {

   9:     var export = new SchemaExport(cfg).SetOutputFile("Script.sql");

  10:  

  11:     //send the script to standard output and execute it

  12:     export.Execute(useStdOut: true, execute: true, justDrop: false);

  13:     //or

  14:     //send all lines of the script to the System.Console.WriteLine method

  15:     export.Execute(scriptAction: System.Console.WriteLine, execute: false, justDrop: false);

  16: }

NHibernate Pitfalls: Versioned Entities Are Not Batcheable

This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

This is a problem similar to the one with native id generators. Basically, because there are different versioning strategies – timestamp, counter, native, etc, – NHibernate needs to issue a SELECT after a versioned entity is INSERTEd or UPDATEd. While this wouldn’t be necessary when NHibernate manages the version on the “client side”, like:

   1: UPDATE MyEntity SET Version = 2 WHERE ...;

   2: //or

   3: UPDATE MyEntity SET Version = GETDATE() WHERE ...;

But not if the version is handled on the database side, like when using SQL Server’s ROWVERSION/TIMESTAMP columns or Oracle’s ORA_ROWSCN pseudo-columns. In these cases, NHibernate needs to issue a SELECT after each INSERT or UPDATE:

   1: UPDATE MyEntity SET ... WHERE ...;

   2: SELECT Version FROM MyEntity WHERE ...;

This breaks batching, because it needs to be done immediately after each INSERT/UPDATE.