NHibernate with LINQ: Error with String Comparisons in VB.NET

If you're in VB.NET using LINQ to NHibernate and you get this error on a simple query:

System.ArgumentException : Expression of type 'System.Int32' cannot be used for return type 'System.Boolean'

Then I've got an explanation and a fix for you.

Here's a query that will produce this error:

Dim result = nhQueryProvider.Where(Function(code) code.Name = "OPEN")

If you load up the NHibernate.Linq code and debug through it, you find that the Expression being evaulated is not what you'd guess. You'd think it would be something simple:

  • code.Name = "OPEN"

But actually it's something like this:

  • CompareString(code.Name, "OPEN") = 0

So that at least gives a clue about where the Int32/Boolean confusion is coming from. Here is an old explanation of what the VB compiler is doing to for you:

http://blogs.msdn.com/vbteam/archive/2007/09/18/vb-expression-trees-string-comparisons.aspx

It's pretty easy to modify the NHibernate.Linq's ExpressionVisitor with the fix suggested in the post above.

I am using NHibernate.Linq 1.0.0.4000. I see that Linq support is currently in NHibernate Core's trunk, and that it's changed quite a bit since the GA, so hopefully the next version will handle VB string comparison in a more predictable way.

Since the fix in the link above is in VB, here's the C# translation for your convenience:

private static BinaryExpression FixVbStringComparison(BinaryExpression exp) { if (exp.Left.NodeType == ExpressionType.Call) { var compareStringCall = (MethodCallExpression)exp.Left; if (compareStringCall.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" && compareStringCall.Method.Name == "CompareString") { var arg1 = compareStringCall.Arguments[0]; var arg2 = compareStringCall.Arguments[1]; switch (exp.NodeType) { case ExpressionType.LessThan: return Expression.LessThan(arg1, arg2); case ExpressionType.LessThanOrEqual: return Expression.GreaterThan(arg1, arg2); case ExpressionType.GreaterThan: return Expression.GreaterThan(arg1, arg2); case ExpressionType.GreaterThanOrEqual: return Expression.GreaterThanOrEqual(arg1, arg2); default: return Expression.Equal(arg1, arg2); } } } return exp; }

Comments !

links

social