Calling a Stored Procedure as part of a NHibernate transaction


The scenario

Today I had the need to call a stored procedure after some domain objects got updated. Those domain objects are persisted via NHibernate. The question here is not whether it’s good or not to have calls to sprocs mixed with NHibernate persistence because this can be argued but sometimes you have no choice when dealing with legacy code.

This is all in the context of an asp.net application with a SQL Server database.

The problem

The root of the problem I faced was that we are using a DAO pattern where a NHibernate session is started at the beginning of a request and closed at the end of the request.

My first approach was to do my objects updates and then call a method in my data access layer executing the stored procedure through ADO.NET. The problem with this was that the changes done to the objects are not persisted into the database until the session closed and the transaction committed. As a result, the stored procedure was run immediately and my update statements issued afterward.

I then thought that all I had to do was flush my NHibernate session before I exec the sproc to commit my changes to the database. However, for some reason that created some lock or pending session somewhere so my ado.net connection attempt timed out.

The solution

The idea of flushing the session and then executing the sproc was close but the last missing piece was to call the sproc via NHibernate using the same session as opposed to ADO.NET. My code ended up looking like this:


// flush the NHibernate session to commit changes
Session.Flush();

// execute the stored procedure
IQuery query = Session.CreateSQLQuery("exec MySprocName @param=:param1");
query.SetString("param1", data);
query.ExecuteUpdate();

Hope this helps

WILT: Query by Criteria with clause on component property with NHibernate


It took me a little bit to figure this one out but it makes sense and it’s pretty simple once we know:

Let’s say I have a class MyFirstClass with a component of type MySecondClass and I want to write a query to retrieve all MyFirstClass objects where the ID of MySecondClass is 1.
My first attempt went like this:

Session.CreateCriteria(typeof(MyFirstClass)
   .Add(NHibernate.Criterion.Expression
     .Eq("MySecondClass.ID", "1"));
That didn’t work because NHibernate doesn’t understand what I meant with MySecondClass.ID.
The solution is simply to use a sub criteria like so:
Session.CreateCriteria(typeof(MyFirstClass)
  .CreateCriteria("MySecondClass")
    .Add(NHibernate.Criterion.Expression
      .Eq("ID", "1"));

It is important to notice that the sub criteria is created using the Property name

Mapping a nullable bit column to an enum with NHibernate


I recently had to map an enum with 3 possible values (Pending, Approved, denied) to a nullable bit field in a SQL database. This type of mapping is not supported natively by NHibernate which by default translates enum values to their integer representation. I found several articles on handling the mapping to a string which is pretty straight forward using the … type but I haven’t found anything about this particular scenario.

This is where custom user types come to the rescue and this is what I am going to explain in this article.

To create a custom user type, we just need to create a class that implements NHibernate.UserTypes.IUserType. In our case, the implentation is pretty easy with the only methods that required a little bit of thinking being NullSafeGet and NullSafeSet.
This is how the class looks like:

public class NullableApprovalStatusType : IUserType
{
    public bool Equals(object x, object y)
    {
        return x == null ? y == null : x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names,
                              object owner)
    {
        bool? dbValue = (bool?) NHibernateUtil.Boolean
                                 .NullSafeGet(rs, names);
        switch (dbValue)
        {
            case true:
                return ApprovalStatusType.Approved;
            case false:
                return ApprovalStatusType.Denied;
            default:
                return ApprovalStatusType.Pending;
        }
    }

    public void NullSafeSet(IDbCommand cmd, object value,
                            int index)
    {
        var obj = (ApprovalStatusType) value;
        bool? dbValue = null;
        switch (obj)
        {
            case ApprovalStatusType.Approved:
                dbValue = true;
                break;
            case ApprovalStatusType.Denied:
                dbValue = false;
                break;
            case ApprovalStatusType.Pending:
                dbValue = null;
                break;
        }
        NHibernateUtil.Boolean.NullSafeSet(cmd, dbValue,index);
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target,
                          object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public SqlType[] SqlTypes
    {
        get { return new[] {new SqlType(DbType.Boolean)}; }
    }

    public Type ReturnedType
    {
        get { return typeof(ApprovalStatusType); }
    }

    public bool IsMutable
    {
        get { return false; }
    }
}

Now that we have our custom user type ready we can just do out mapping:

<property name="ApprovalStatus" column="is_approved"
          not-null="false"
          type="MyNamespace.NullableApprovalStatusType,
                MyAssembly" />

It is nice to notice that the custom user type doesn’t have to be in the same namespace or assembly as the mapped class which allows us to keep it in the data access layer and not introduce any NHibernate dependency to the business logic or domain objects.

WILT: NHibernate – An association from the table MyTable refers to an unmapped class: MyClass


If you are sure that you already created the mapping for MyClass, the first thing to check is that you change the BuildAction Property for the mapping file MyClass.hbm.xml to Embedded Resource.

This can be done by right-clicking on the mapping file in Solution Explorer and then clicking on Properties. The BuildAction is the first property in the list.