Showing posts with label LINQ. Show all posts
Showing posts with label LINQ. Show all posts

Tuesday, November 1, 2011

Strongly Typed HQL


If you're using NHibernate, you have 3 main options to execute a query against the DB: Criteria API, HQL and SQL. The last one won't be relevant to our discussion.

For a long time, the names of the properties were a weakness point since they were represented by strings. For example:

var crit = Session.CreateCriteria(typeof(Person));
crit.Add(NHibernate.Criterion.Expression.Eq("ID", someVal));

Lately, Criteria API has an extension to support Lambda expressions and therefore can be strongly typed:

var crit = Session.CreateCriteria(typeof(Person));
crit.Add<Person>(p => p.ID == someVal)

But in some complicated cases - HQL is inevitable, and since HQL is represented by string - refactoring can be very painful. For example:

string hql = "select p from Person p where p.ID=:someVal"

To avoid this problem, I've created 2 methods. To use these methods, simply locate them in the base class of all the classes that build HQL quries. In our case it was BaseRepository which is the base class for all the Repositories (if you're following DDD). These 2 methods are:

Class<T>();
Prop<T>(Expression<Func<T, object>> property);

I will show the implementation soon, but first an example:

string hql = "select p from " 
+ Class<Person>() + " p where p." + Prop<Person>(x => x.ID) + "=:someVal"

And the implementation:

public string Class<T>()
{
    return typeof(T).ToString();
}

public string Prop<T>(Expression<Func<T, object>> property)
{
    if (property.Body.NodeType == ExpressionType.MemberAccess)
    {
        return (property.Body as MemberExpression).Member.Name;
    }
    else if (property.Body.NodeType == ExpressionType.Convert
        && (property.Body as UnaryExpression).Operand.NodeType == ExpressionType.MemberAccess)
{
        return ((property.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
}

    return "";
}