Linq to NHibernate and Dynamic LINQ - query caching not working

dynamic-linq linq linq-to-nhibernate nhibernate

Question

I have problem with the NHibernate's second level cache. When I use query:

        var items1 = Session.Query<Row>()
            .Cacheable();
            .Fetch(x => x.Field)
            .OrderBy(x => x.Field.Value)
            .ToList();

Everything is fine - the query is cached. But when I want to use Dynamic Linq (a link):

       var items2 = Session.Query<Row>()
            .Cacheable();
            .Fetch(x => x.Field)
            .OrderBy("Field.Value")
            .ToList();

The query is not cached. Interesting thing is that, when I delete code line:

            .Fetch(x => x.Field)

caching works again. So the problem is with using Fetch and dynamic linq OrderBy methods together.

EDIT:

When I try do debug NH code (QueryKey class), debugger tells me that these two queries do not have the same ResultTransformer (and deeper: a listTransformation private instance).

Any ideas?

Chris

1
3
8/8/2012 9:55:52 AM

Accepted Answer

Ok, I know what is the reason.

Dynamic Linq doesn't use Parameter Names in Linq Expressions. E.g. if I want to sort using lambda statemant, I write:

query.OrderBy(item => item.Name)

Above we see an item lambda parameter name.

When I use Dynamic linq:

query.OrderBy("Name")

in the result Queryable the lambda parameter in OrderBy mehod has no name (like item written above). We can illustrate the result like this:

query.OrderBy( => .Name)

And now, when NHibernate is decoding that Queryable expression and finds there an expression parameter that has no name, NH gives it a random name using GUID class. So every ordering using dynamic linq produces a Queryable Expression that has inconstant lambda parameter. This is the reason why NHibernate thinks that: query.OrderBy("Name") and query.OrderBy("Name") are not the same - they have another lamda parameters generated every time from scratch.

SOLUTION

If you want to fix it, you have to modify Dynamic Linq library.

  1. In method ExpressionParser.ProcessParameters change line:

    if (parameters.Length == 1 && String.IsNullOrEmpty(parameters[0].Name))
    

    to:

    if (parameters.Length == 1 && (parameters[0].Name == "it" || String.IsNullOrEmpty(parameters[0].Name)))
    
  2. In method DynamicQueryable.OrderBy change line:

    Expression.Parameter(source.ElementType, "")
    

    to:

    Expression.Parameter(source.ElementType, "it")
    

Now, query.OrderBy("Name") will produce query.OrderBy(it => it.Name).

Cheers!

2
8/14/2012 2:00:18 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow