使用 String.IsNullOrEmpty(string) 和 Nhibernate 创建动态 Linq 表达式
Posted
技术标签:
【中文标题】使用 String.IsNullOrEmpty(string) 和 Nhibernate 创建动态 Linq 表达式【英文标题】:Creating dynamic Linq Expression using String.IsNullOrEmpty(string) and Nhibernate 【发布时间】:2014-02-15 22:01:22 【问题描述】:我正在尝试使用表达式创建动态休眠查询。我对 Contains、StartsWith 和 EndsWith 等函数没有任何问题,但我似乎无法让它与 IsNullOrEmpty 一起使用。这是一些上下文:
包含:
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)));
在这一切的最后,表达式在调试器中等于这个:
expression = x.MyStringProperty ;
然后我把它变成一个 lambda 表达式:
var finalExpression = Expression.Lambda<Func<MyType, bool>>(expression, param);
最后,finalExpression是这样的:
x => x.MyStringProperty.Contains("Does it contain this string");
当我通过 nhibernate 运行它时,它完全符合我的要求。不过,有了 IsNullOrEmpty,这就是我所拥有的:
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);
最后,表达式等于:
expression = IsNullOrEmpty(x.MyStringProperty)
在 lambda 转换之后变成:
finalExpression = x => IsNullOrEmpty(x)
这看起来和它应该的完全一样(虽然我承认它可能应该读取 string.IsNullOrEmpty(x)),但是当我通过 nhibernate 运行它时,我得到了错误:
NotSupportedException
Message: Boolean IsNullOrEmpty(System.String)
有谁知道这是为什么?如果我运行一个非动态查询并像这样手写一个 where 子句,它就可以正常工作:
nhibernateDataProvider.Where(x => string.IsNullOrEmpty(x.MySTringProperty));
有人知道这是为什么/如何解决这个问题吗?
编辑:
我为什么要这样做:
在我的 Web 层中,我向用户显示了这个 x.MyStringProperty 数据。他们有能力通过这个属性进行过滤,我希望能够通过这些字符串方法来过滤数据。 Web 层只是将这些函数传回:
BeginsWith
EndsWith
Contains
IsNullOrEmpty
NotIsNullOrEmpty
从这些名称中,我可以使用上面的代码直接将它们转换为字符串方法。因此,我可以传递 Web 层中的任何类型,并能够过滤任何字符串属性。这非常强大,因为对于我所有的数百个类,我可以使用一种方法来处理我对每个类的过滤。正如我之前所说,IT 使用非静态方法,因为构建的表达式是:
x -> x.MyStringProperty.NonStaticMethod("SomeFilterValue");
在 Expression.Call 的文档中说得对,您也应该能够使用静态方法来执行此操作。由于它适用于非静态方法,因此必须有一种方法来执行 IsNullOrEmpty 使得表达式变为
x -> string.StaticMethod(x.MyStringProperty)
我敢打赌,如果我创建表达式,它会起作用
x -> x.MySTringProperty == null || x.MySTringProperty == ""
但这是一种解决方法,作为一名程序员,我觉得我需要找出如何使用静态方法来完成上述工作。
【问题讨论】:
【参考方案1】:我只是不确定您要在这里实现什么。 动态表达式查询语言已经存在:它是内置的 LINQ 提供程序。但是,让我们尝试为您提供有关其实现的更多信息。
当内置的 Linq 提供程序接收到由表达式树表示的查询时,访问者模式用于将其转换为 SQL(带有中间 HQL 步骤)。一个强大的部分是接口IHqlGeneratorForMethod
代表的方法检查
public interface IHqlGeneratorForMethod
IEnumerable<MethodInfo> SupportedMethods get;
HqlTreeNode BuildHql(MethodInfo method, Expression targetObject
, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder
, IHqlExpressionVisitor visitor);
这里重要的部分是一组实现者:
DictionaryItemGenerator
DictionaryContainsKeyGenerator
EqualsGenerator
BoolEqualsGenerator
MathGenerator
AnyHqlGenerator
AllHqlGenerator
MinHqlGenerator
MaxHqlGenerator
CollectionContainsGenerator
HqlGeneratorForExtensionMethod
StartsWithGenerator // StartsWith
EndsWithGenerator // EndsWith
ContainsGenerator // Contains
ToLowerGenerator
ToUpperGenerator
SubStringGenerator
IndexOfGenerator
ReplaceGenerator
TrimGenerator
如您所见,有Contains
、EndsWith
和StartsWith
的负责人。但是那里找不到IsNullOrEmpty。
换句话说,无论您在全局中做什么,您的 IsNullOrEmpty 都应该以这样的语句结束:
.Where(x => x.MyProperty == null || x.MyProperty == "")
【讨论】:
【参考方案2】:7 年后,寻找正确答案但未能在 *** 中找到,使用 System.Linq.Expressions,版本 4.2.2.0 找到了解决方案,分别使用 Expression.IsTrue(Expression.Call(isNull, expression))
和 Expression.IsFalse
等非空值方法。这对我来说是一笔交易。
【讨论】:
您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。以上是关于使用 String.IsNullOrEmpty(string) 和 Nhibernate 创建动态 Linq 表达式的主要内容,如果未能解决你的问题,请参考以下文章
string.IsNullOrEmpty和string.IsNullOrWhiteSpace方法的区别
转载:string.IsNullOrEmpty和string.IsNullOrWhiteSpace方法的区别
String.IsNullOrEmpty()和String.IsNullOrWhiteSpace()