Monday, July 19, 2010

NHibernate Detached Criteria is not Reusable

While working on a paging feature for our application I discovered that the NHibernate detached criteria is not reusable. My goal was to create a single call to a repository using one detached criteria. The Idea was to reuse the detached criteria to perform two queries. One query to retrieve the total number records. The second query to retrieve a list of items for the specified page number and number of records per a page.

On the repository we have the following method.
QueryResult<T> FindBy(DetachedCriteria query,int pageNumber,int numberOfItemsToDisplay);

The QueryResult returned from the repository has a total and the items for the requested page.
public class QueryResult<T>
    {
        public int TotalNumberOfItems { get; private set; }
        public IEnumerable<T> Items { get; private set; }

        public QueryResult(int totalNumberOfItems, IEnumerable<T> items)
        {
            TotalNumberOfItems = totalNumberOfItems;
            Items = items;
        }
    }

Here is my implementation of FindBy. I had a few helper methods but removed them to fully illustrate the problem.
   public QueryResult<T> FindBy(DetachedCriteria query, int pageNumber, int numberOfItemsToDisplay)
        {
            var pageIndex = pageNumber - 1;
            var firstResult = 0;

            if (pageIndex != 0)
                firstResult = pageIndex * numberOfItemsToDisplay;

            ICriteria executableQuery = query.GetExecutableCriteria(CurrentSession());
            executableQuery.SetProjection(Projections.RowCount());

            var count =  executableQuery.UniqueResult<int>();

            query.SetProjection(null);
            query.SetResultTransformer(CriteriaSpecification.RootEntity);

            var items = FindBy(query.SetFirstResult(firstResult).SetMaxResults(numberOfItemsToDisplay));

            return new QueryResult<T>(count,items);
        }

The confusing part
ICriteria executableQuery = query.GetExecutableCriteria(CurrentSession());
Calling getExecutableCritieria returns an ICrtieria object. One would think that the criteria object does not have a connection to the detached query object. Calling the code below should not change the detached criteria.

executableQuery.SetProjection(Projections.RowCount());
var count =  executableQuery.UniqueResult<int>();
The quick fix is to set the projection to null and reset the result transformer.

//Reset
query.SetProjection(null);
query.SetResultTransformer(CriteriaSpecification.RootEntity);

//Excute new query
var items = FindBy(query.SetFirstResult(firstResult).SetMaxResults(numberOfItemsToDisplay));

In Summary
I find the behaviour of the detached criteria object to be somewhat odd. It might just be a misunderstanding on my part but the API led me to believe that the ICriteria object had no relationship to the detached query. The coupling between the ICriteria object and detached criteria was a big surprise. If I were to ask I bet the NHibernrate/Hibernate team or even Oren Eini could provide me with an explanation.

Sunday, July 18, 2010

Razor View Engine for Asp.Net MVC and More

Microsoft has done it again. They are releasing a new view engine for Asp.Net MVC code named Razor. Even more impressive is the fact that you will be able to use more than one view engine in your application. This means that you can develop an application using the web forms view engine, spark and razor. To learn more head over to Scott Gu's blog. The new view engine is slated to be released with the next version of Asp.net MVC.

In other news Microsoft is working on two other products: IIS Express and SQL Server Compact Edition 4. With IIS Express you can have a full featured web server that does not require administrative privileges. This is wonderful news for the security conscious developer with a locked down machine(for example this guy). IIS Express unlike the built-in web server in visual studio will support SSL and url rewriting. From what I can tell it will do pretty much anything IIS 7 does. According to the Gu it will be released as an patch for Visual Studio 2010 later in the year. All versions of Visual Studio in the future will be shipped with IIS Express.

SQL Server Compact Edition 4 is another cool product that will work with Asp.Net MVC. SQL CE doesn't require any installation. It's as simple as dropping a few dlls in the bin of your application. When your application starts SQL CE is loaded into memory and when the application stops it is unloaded. Even better is the ability to easily upgrade from SQL CE to SQL server express, SQL server or  even SQL Azure. This means that you can start an application with SQL CE and then upgrade when your application grows beyond the limitations of SQL CE. Visual Studio 2010 will also feature support for SQL CE. It might just be me but Visual Studio is starting to become a one stop shop for everything, and I like it. Fortunately SQL CE does not support stored procedures. Stored procedures are evil so no big deal there. It's also important to mention that you do not have to change any code to work with SQL CE. It should be as easy as changing your connection string.