Reputation: 2842
I'm trying to create a dynamic nhibernate query using Expressions. I have no problem with functions like Contains, StartsWith and EndsWith, but I cannot seem to get it to work with IsNullOrEmpty. Here's some context:
Contains:
MethodInfo contains = typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
ParameterExpression param = Expression.Parameter(typeof(MyType), "x");
Expression expression = null;
PropertyInfo info = typeof(MyType).Property("MyStringProperty");
expression = Expression.Property(param, info);
expression = Expression.Call(expression, info, Expression.Constant("Does it contain this string", typeof(string)));
At the end of all this, expression is equal to this in the debugger:
expression = { x.MyStringProperty };
I then turn this into a lambda exrpression:
var finalExpression = Expression.Lambda<Func<MyType, bool>>(expression, param);
At the end of this, finalExpression is this:
x => x.MyStringProperty.Contains("Does it contain this string");
When I run this through nhibernate, it does exactly what I want. With IsNullOrEmpty though, this is what I have:
MethodInfo isNull = typeof(string).GetMethod("IsNullOrEmpty", new Type[] { typeof(string) } );
ParameterExpression param = Expression.Parameter(typeof(MyType), "x");
PropertyInfo info = typeof(MyType).GetProperty("MyStringProperty");
expression = Expression.Property(param, info);
expression = Expression.Call(isNull, expression);
At the end of all this, expression is equal to:
expression = { IsNullOrEmpty(x.MyStringProperty) }
And after the lambda conversion it turns to:
finalExpression = { x => IsNullOrEmpty(x) }
This looks exactly like it should (although I admit maybe it should read string.IsNullOrEmpty(x)), but when I run it through nhibernate, I get the error:
NotSupportedException
Message: Boolean IsNullOrEmpty(System.String)
Does anyone know why this is? If I run a not dynamic query and hand write a where clause like this, it works without problem:
nhibernateDataProvider.Where(x => string.IsNullOrEmpty(x.MySTringProperty));
Anyone know why this is/how to fix this?
Edit:
Why am I trying to do this:
In my web layer I have this x.MyStringProperty data displayed to the user. They have the ability to filter by this property, and I want to be able to filter the data by these string methods. The web layer simply passes these functions back:
BeginsWith
EndsWith
Contains
IsNullOrEmpty
NotIsNullOrEmpty
From these names I can directly turn them into the string methods using the above code. Because of this, I can pass any type I have in my web layer and be able to filter any string property. This is very powerful because for all of my hundreds of classes, I can have one method that takes care of my filtering for every class. As I said before, IT works with the nonstatic methods, because the Expression built is:
x -> x.MyStringProperty.NonStaticMethod("SomeFilterValue");
Is says right in the documentation for Expression.Call, that you should be able to do this with static methods as well. Since it works for the nonstatic methods, there has to be a way to do IsNullOrEmpty such that the expression becomes
x -> string.StaticMethod(x.MyStringProperty)
I bet you it would work if I create the expression
x -> x.MySTringProperty == null || x.MySTringProperty == ""
But that is a work around, and as a programmer, I feel out of principle I need to find out how to do the above using the static method.
Upvotes: 2
Views: 2711
Reputation: 1
7 years later, looking for the right answer and failed to find in StackOverflow, using System.Linq.Expressions, Version 4.2.2.0 found solution with methods like Expression.IsTrue(Expression.Call(isNull, expression))
and respectively Expression.IsFalse
for non null values. That sets the deal for me.
Upvotes: -1
Reputation: 123861
I am simply not sure what you are trying to achieve here. The dynamic expression query language is already there: it is the built-in LINQ provider. But let's try to give you more information about its implementation.
When the built-in Linq provider recieves the query, represented by expressions tree, a visitor pattern is used for its conversion into the SQL (with a middle HQL step). One powerful part is the method inspection represented by interface IHqlGeneratorForMethod
public interface IHqlGeneratorForMethod
{
IEnumerable<MethodInfo> SupportedMethods { get; }
HqlTreeNode BuildHql(MethodInfo method, Expression targetObject
, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder
, IHqlExpressionVisitor visitor);
}
The important part here is a set of implementors:
DictionaryItemGenerator
DictionaryContainsKeyGenerator
EqualsGenerator
BoolEqualsGenerator
MathGenerator
AnyHqlGenerator
AllHqlGenerator
MinHqlGenerator
MaxHqlGenerator
CollectionContainsGenerator
HqlGeneratorForExtensionMethod
StartsWithGenerator // StartsWith
EndsWithGenerator // EndsWith
ContainsGenerator // Contains
ToLowerGenerator
ToUpperGenerator
SubStringGenerator
IndexOfGenerator
ReplaceGenerator
TrimGenerator
As you can see, there are the responsibles for Contains
, EndsWith
and StartsWith
. But IsNullOrEmpty cannot be found there.
Other words, regardless what you are doing in a global, your IsNullOrEmpty should end up in a statement like this:
.Where(x => x.MyProperty == null || x.MyProperty == "")
Upvotes: 3