Try fast search NHibernate

29 July 2010

NHibernate LINQ provider extension

In NHibernate almost all OO query systems (HQL, Criteria, QueryOver) are extensible. LINQ is, in its nature, a big extensible extension, but can you extend our LINQ-provider to translate your LINQ-extension in SQL ?
As usual in NHibernate, the answer is : yes, you can!!

The LINQ extension

As example I’m going to use an extension of string to mimic the SQL LIKE clause.
public static class MyLinqExtensions
    public static bool IsLike(this string source, string pattern)
        pattern = Regex.Escape(pattern);
        pattern = pattern.Replace("%", ".*?").Replace("_", ".");
        pattern = pattern.Replace(@"\[", "[").Replace(@"\]","]").Replace(@"\^", "^");

        return Regex.IsMatch(source, pattern);
I can use my extension in memory but what I need is instruct NHibernate about its translation for my persistence-queries.

The integration

The integration point is a class implementing : ILinqToHqlGeneratorsRegistry
The LinqToHqlGeneratorsRegistry provides the way to recognize and translate methods and properties of varios classes. Our DefaultLinqToHqlGeneratorsRegistry can manage LINQ extensions as Any, All, Min, Max etc., methods as StratsWith, EndsWith, Contains, IndexOf etc. or properties as Year, Month, Day, Length etc.
First of all I have to implements a IHqlGeneratorForMethod. NHibernate provides a cooked base class and my implementation will look as:

public class IsLikeGenerator : BaseHqlGeneratorForMethod
    public IsLikeGenerator()
        SupportedMethods = new[] {ReflectionHelper.GetMethod(() => MyLinqExtensions.IsLike(null, null))};

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
        ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
        return treeBuilder.Like(visitor.Visit(arguments[0]).AsExpression(),

Having the HQL generator for my extension I can implements my ILinqToHqlGeneratorsRegistry extending the default implementation.

public class MyLinqToHqlGeneratorsRegistry: DefaultLinqToHqlGeneratorsRegistry
    public MyLinqToHqlGeneratorsRegistry():base()
        RegisterGenerator(ReflectionHelper.GetMethod(() => MyLinqExtensions.IsLike(null, null)),
                          new IsLikeGenerator());

The configuration

The last step to use my IsLike extension to query the DB is the configuration of my LinqToHQLGeneratorsRegistry.
The name of the property for the XML configuration is : linqtohql.generatorsregistry
In NHibernate 3 you can use the Loquacious-configuration :


 And now...

var contacts = (from c in db.Customers where c.ContactName.IsLike("%Thomas%") select c).ToList();

Welcome to the world of options,
Welcome to NHibernate3!!!

08 July 2010

Enhanced Query Object

One of the annoying thing in our daily work is the modification of the Repository/DAO interface, and implementation, each time a new use-case, of our application, needs a new query.

The three solutions available so far

The Query Object pattern was described by Martin Fowler. I like its short definition:
An object that represents a database query.
What I don’t like so much is its long description:
A Query Object is an interpreter [Gang of Four], that is, a structure of objects that can form itself into a SQL query.
A good example of Query Object is our dear ICriteria with all its classes. The problem is that I can’t expose neither ICriteria nor a concrete class using it because I don’t want expose nothing using NHibernate.
Another possible solution is the Specifications Pattern (by Eric Evans and Martin Fowler).
Specification is again very powerful especially because easy to test. In .NET we have various implementations/interpretations based on LINQ. The advantage is basically that you can test your specification and your specification-composition in RAM… sure… hoping for that your LINQ provider can then efficiently translate it in SQL.
The last is a repository implementing IQueriable (as proposed here) with its pro/cons:
  • Easy to test.
  • LINQ queries, for persistence, wrote every where.
  • Hope that your LINQ provider can then efficiently translate it in SQL.

The fact

In NHibernate we have at least six ways to query our persistence (have a look to this post). I can choose the query-system that best fit my needs of balance between code-readability, code-maintainability and query-performance.
Why I should limit myself in using just one ?
What I need is a solution to avoid the continuous modification of the repository’s interface maintaining the advantage NHibernate gives to me.

Enhanced Query Object

An object that represent a query. The responsibility of a EQO is returns the query results.
In general you will express a EQO as an interface placed in the same assembly where you are putting your IRepository interfaces. An example could look like:
public interface IContactByNameQuery
    string PartialFirstNameOrLastName    { get; set; }
    IPagedResults<Contact> GetAll(int pageSize, int pageNumber);
because the EQO is responsible to return the results of the query, in its implementation I can use whatever the persistence framework gives to me. I can add EQOs to my system without touch existing code. Because a EQO is an interface I can easily mock it. Perhaps I can’t test it quickly in RAM… perhaps… but in general I prefer to write integration tests (tests hitting a well-known-DataBase) instead test my queries using a fake-database.
The implementation of the above EQO, for NHibernate, could look as:
public class ContactByNameQuery : IContactByNameQuery
    private readonly ISessionFactory sessionFactory;

    public ContactByNameQuery(ISessionFactory sessionFactory)
        this.sessionFactory = sessionFactory;

    #region IContactByNameQuery Members

    public string PartialFirstNameOrLastName { get; set; }
    public IPagedResults<Contact> GetAll(int pageSize, int pageNumber)
        var query = sessionFactory.GetCurrentSession().QueryOver<Contact>();
        if (!string.IsNullOrWhiteSpace(PartialFirstNameOrLastName))
                Restrictions.On<Contact>(c => c.FirstName).IsLike(PartialFirstNameOrLastName, MatchMode.Anywhere) |
                Restrictions.On<Contact>(c => c.LastName).IsLike(PartialFirstNameOrLastName, MatchMode.Anywhere)
        query.OrderBy(c => c.LastName).Asc.ThenBy(c => c.FirstName);

        var queryCount = query.ToRowCountQuery();

        var contacts = query.Take(pageSize).Skip((pageNumber -1) * pageSize).Future<Contact>();
        var count = queryCount.FutureValue<int>().Value;
        return new PagedResults<Contact>(count, contacts);


but you are completely free to implement it using LINQ, HQL, Criteria, H-SQL, SQL, NamedQuery or whatever you feel comfortable with.

How create a concrete instance of EQO ?

Using exactly the same identical way you are using for your concrete implementation of Repositories or DAOs implementations.
Try it and let me know how you feel.

02 July 2010

Mercurial problem pushing .Net DLL

This is a story of a pain with an happy end.

As you probably know Mercurial has some nasty problems with large files, even worst when those files are binary. In ConfORM I’m using Mercurial and, as you know, ConfORM work with NHibernate’s trunk. I have to update the Lib folder quite often and I don’t want to find a “workaround” to the Mercurial’s “problem”.

The short story

The story begin fixing NH-2230. After that I have compiled and then actualized ConfORM external libraries and committed in my clone. Then I was working in my clone committing some changes to support the NHibernate new improvement… everything nice and fast.
Before begin the implementation of a new default-pattern-applier I have decided to push all changes to the public repository.

Ok it is easy… only a “push”… the push seems working… working… working… working… working… 30 minutes and still working… working… working…

Ok, my friend!! I suspect you're stuck.

The solution

After Googling and Googling, and mail, and chats, I have found information about PDF (see this wiki).

The solution for .NET projects is add the follows lines to your .hg\hgrc
**.dll = internal:local
**.exe = internal:local
**.pdb = internal:local

The push, before ask you the user&password and after the input of the password, will take a while (few minutes) but at least it work as expected.

UPDATE: The problem was not Mercurial but the push in GoogleCode.