nhibernateoracle11gcastle-windsorlinq-to-nhibernatewindsor-nhfacility

NHibernate (3.1.0.4000) NullReferenceException using Query<> and NHibernate Facility


I have a problem with NHibernate, I can't seem to find any solution for. In my project I have a simple entity (Batch), but whenever I try and run the following test, I get an exception. I've triede a couple of different ways to perform a similar query, but almost identical exception for all (it differs in which LINQ method being executed).

The first test:

[Test]
public void QueryLatestBatch()
{
    using (var session = SessionManager.OpenSession())
    {
        var batch = session.Query<Batch>()
            .FirstOrDefault();

        Assert.That(batch, Is.Not.Null);
    }
}

The exception:

System.NullReferenceException : Object reference not set to an instance of an object.
at NHibernate.Linq.NhQueryProvider.PrepareQuery(Expression expression, ref IQuery query, ref NhLinqExpression nhQuery)
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression)
at System.Linq.Queryable.FirstOrDefault(IQueryable`1 source)

The second test:

[Test]
public void QueryLatestBatch2()
{
    using (var session = SessionManager.OpenSession())
    {
        var batch = session.Query<Batch>()
            .OrderBy(x => x.Executed)
            .Take(1)
            .SingleOrDefault();

        Assert.That(batch, Is.Not.Null);
    }
}

The exception:

System.NullReferenceException : Object reference not set to an instance of an object.
at NHibernate.Linq.NhQueryProvider.PrepareQuery(Expression expression, ref IQuery query, ref NhLinqExpression nhQuery)
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression)
at System.Linq.Queryable.SingleOrDefault(IQueryable`1 source)

However, this one is passing (using QueryOver<>):

[Test]
public void QueryOverLatestBatch()
{
    using (var session = SessionManager.OpenSession())
    {
        var batch = session.QueryOver<Batch>()
            .OrderBy(x => x.Executed).Asc
            .Take(1)
            .SingleOrDefault();

        Assert.That(batch, Is.Not.Null);
        Assert.That(batch.Executed, Is.LessThan(DateTime.Now));
    }
}

Using the QueryOver<> API is not bad at all, but I'm just kind of baffled that the Query<> API isn't working, which is kind of sad, since the First() operation is very concise, and our developers really enjoy LINQ.

I really hope there is a solution to this, as it seems strange if these methods are failing such a simple test.

EDIT

I'm using Oracle 11g, my mappings are done with FluentNHibernate registered through Castle Windsor with the NHibernate Facility. As I wrote, the odd thing is that the query works perfectly with the QueryOver<> API, but not through LINQ.


Solution

  • There is an issue with the current implementation of the LINQ extensionmethods for NHibernate 3.1.0.4000 used together with NHibernate Facility 2.0RC (and previous versions) (see: https://nhibernate.jira.com/browse/NH-2626 and discussion here: http://groups.google.com/group/castle-project-devel/browse_thread/thread/ac90148a8d4c8477)

    The fix I am using at the moment is to simply ignore the LINQ extensionmethods provided by NHibernate and create it myself. They're really just one-liners:

    public static class NHibernateLinqExtensions
    {
        /// <summary>
        /// Performs a LINQ query on the specified type.
        /// </summary>
        /// <typeparam name="T">The type to perform the query on.</typeparam>
        /// <param name="session"></param>
        /// <returns>A new <see cref="IQueryable{T}"/>.</returns>
        /// <remarks>This method is provided as a workaround for the current bug in the NHibernate LINQ extension methods.</remarks>
        public static IQueryable<T> Linq<T>(this ISession session)
        {
            return new NhQueryable<T>(session.GetSessionImplementation());
        }
    
        /// <summary>
        /// Performs a LINQ query on the specified type.
        /// </summary>
        /// <typeparam name="T">The type to perform the query on.</typeparam>
        /// <param name="session"></param>
        /// <returns>A new <see cref="IQueryable{T}"/>.</returns>
        /// <remarks>This method is provided as a workaround for the current bug in the NHibernate LINQ extension methods.</remarks>
        public static IQueryable<T> Linq<T>(this IStatelessSession session)
        {
            return new NhQueryable<T>(session.GetSessionImplementation());
        }
    }
    

    Then, when I need to do a LINQ query, I just use session.Linq<EntityType>() instead of session.Query<EntityType>.

    Hope it helps someone in the same situation that I was.