I'm using NHibernate 3.1.0 and I'm trying to extend the LINQ provider by using BaseHqlGeneratorForMethod
and extending the DefaultLinqToHqlGeneratorsRegistry
as explained in Fabio's post.
For example, to support ToString()
I've created a ToStringGenerator
as below.
internal class ToStringGenerator : BaseHqlGeneratorForMethod
{
public ToStringGenerator()
{
SupportedMethods = new[]
{
ReflectionHelper.GetMethodDefinition<object>(x => x.ToString())
};
}
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.Cast(visitor.Visit(targetObject).AsExpression(), typeof(string));
}
}
and I have registered using
internal class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public CustomLinqToHqlGeneratorsRegistry()
{
this.Merge(new ToStringGenerator());
}
}
etc. So far this works for "static" queries, I can use it like this:
var results = mSession.Query<Project>();
string pId = "1";
results = results.Where(p => p.Id.ToString().Contains(pId));
This translates correctly to its SQL counterpart (using SQL Server 2008)
where cast(project0_.Id as NVARCHAR(255)) like (''%''+@p0+''%'')
The problem arises when I try to use it in combination with Microsoft Dynamic LINQ library (discussed in this Scott Guthrie's post) like this:
var results = mSession.Query<Project>();
string pId = "1";
results = results.Where("Id.ToString().Contains(@0)", pId);
This results in a NotSupportedException with a message of "System.String ToString()" (which was the exact same messages I was getting with the static queries before implementing the classes mentioned above). This exception is being thrown with a source of "NHibernate" and with the StackTrace at "at NHibernate.Linq.Visitors.HqlGeneratorExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression)".
So what am I missing here? What have I done wrong, or what needs to be done to support this scenario?
Supposing the property
Id
of the classProject
it's anInt32
try registering the correspondingInt32.ToString()
method in yourToStringGenerator
class.I had the same problem and fixed it.
At first I want to thank murki for providing the information which got me on my way!
The answer lies partly in Fabio's post. To solve this issue you have to use the
RegisterGenerator
instead of theMerge
method in theCustomLinqToHqlGeneratorsRegistry
constructor. My implementation of theCustomLinqToHqlGeneratorsRegistry
class is as follows:There are two, well defined, separate stages here:
Since you have determined that a static expression works well, the problem lies in 1.
What happens if you do the following?
If it fails, you'll have confirmed it's a problem with Dynamic Linq alone (i.e. it doesn't support the expression you're feeding it), so you'll have to dig into it and patch it.
Semi-related: the
ToStringGenerator
looks useful; could you submit a patch for NHibernate? http://jira.nhforge.org