使用表达式的LINQ过滤器实现 [英] LINQ Filter Implementation with Expressions
问题描述
在MVC4,我提供的搜索框,用户搜索表中的任意值。
所以我在C#
需要帮助多个表达式相结合,形成单一的表达 <落实在服务器端一般过滤器条件/ p>
表达式来; Func键< T,BOOL>>
例如:
表列
MenuText,角色名称(Role.Name映射),ActionName
现在如果用户在ABC的搜索框,可以在任何行中显示的列,需要过滤输入。
模式
公共类菜单
{
公共字符串MenuText {获取;集;}
公共角色角色{获取;集;}
公共字符串ActionName {获取;集;}
}
公共类角色
{
公字符串名称{;设置;}
}
到目前为止,我已经实现
///<总结>
///字符串[]属性property.Name(MenuText,ActionName),包括更深层次的映射名称,如(Role.Name)
///< /总结>
公共静态表达式来; Func键< T,BOOL>> FilterKey< T>(串filterText,PARAMS字符串[]属性)
{
ParameterExpression参数= Expression.Parameter(typeof运算(T));
表达[] = propertyExpressions properties.Select(
X => string.IsNullOrEmpty(x)的GetDeepPropertyExpression(参数x):!NULL).ToArray();
表达式来; Func键< T,BOOL>>谓词= PredicateBuilder.False< T>();
的foreach(在propertyExpressions表达表达式)
{
VAR TOLOWER = Expression.Call(表达式的typeof(串).GetMethod(ToLower将System.Type.EmptyTypes));
VAR像= Expression.Call(TOLOWER的typeof(串).GetMethod(包含),Expression.Constant(filterText.ToLower()));
// TODO:结合表达式,形成单一的表达式来; Func键< T,BOOL>>表达式
}
返回谓语;
}
///<总结>
///要变得更深属性,如Role.Name表达式
///< /总结>
私有静态表达GetDeepPropertyExpression(表达initialInstance,字符串属性)
{
表达式结果= NULL;
的foreach(在property.Split(字符串propertyName的'。'))
{
表达实例=结果? initialInstance;
结果= Expression.Property(例如,propertyName的);
}
返回结果;
}
感谢NinjaNye,我已经借BuildOrExpression从而解决了我的问题。
下面是解决方案
公开静态表达式来; Func键< T,BOOL>> FilterKey< T>(串filterText,PARAMS字符串[]属性)
{
ParameterExpression参数= Expression.Parameter(typeof运算(T));
表达[] = propertyExpressions properties.Select(
X => string.IsNullOrEmpty(x)的GetDeepPropertyExpression(参数x):!NULL).ToArray();
语句,比如= propertyExpressions.Select(表达式=> Expression.Call(表达式的typeof(串).GetMethod(ToLower将Type.EmptyTypes)))选择(TOLOWER =方式>表达.CALL(TOLOWER的typeof(串).GetMethod(包含),Expression.Constant(filterText.ToLower())))骨料和LT; MethodCallExpression,表达>(NULL,(目前,EX)=> BuildOrExpression(电流,前));
返回Expression.Lambda<&Func键LT; T,BOOL>>(如,参数);
}
私有静态表达BuildOrExpression(表达式existingExpression,表达expressionToAdd)
{
如果(existingExpression == NULL)
{
返回expressionToAdd;
}
//建设OR表示每个属性
返回Expression.OrElse(existingExpression,expressionToAdd);
}
私有静态表达GetDeepPropertyExpression(表达initialInstance,字符串属性)
{
表达式结果= NULL;
的foreach(在property.Split(字符串propertyName的'。'))
{
表达实例=结果? initialInstance;
结果= Expression.Property(例如,propertyName的);
}
返回结果;
}
In MVC4 , I am providing Search box to the user to search any value in Table. So I am implementing Generic Filter Condition at server side in C#
Need a help to combine multiple expressions to form single expression
Expression<Func<T, bool>>
For Example
Table Columns
MenuText, Role Name (Role.Name mapping), ActionName
Now If user entered in search box for ABC , which can be in any of the rows in shown columns, need to filter.
Model
public class Menu
{
public string MenuText {get;set;}
public Role Role {get;set;}
public string ActionName {get;set;}
}
public class Role
{
public string Name {get;set;}
}
So far I have implemented
/// <summary>
/// string[] properties property.Name (MenuText, ActionName), including deeper Mapping names such as (Role.Name)
/// </summary>
public static Expression<Func<T, bool>> FilterKey<T>(string filterText, params string[] properties)
{
ParameterExpression parameter = Expression.Parameter(typeof (T));
Expression[] propertyExpressions = properties.Select(
x => !string.IsNullOrEmpty(x) ? GetDeepPropertyExpression(parameter, x) : null).ToArray();
Expression<Func<T, bool>> predicate = PredicateBuilder.False<T>();
foreach (Expression expression in propertyExpressions)
{
var toLower = Expression.Call(expression, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
var like = Expression.Call(toLower, typeof(string).GetMethod("Contains"), Expression.Constant(filterText.ToLower()));
//TODO: Combine expressions to form single Expression<Func<T, bool>> expression
}
return predicate;
}
/// <summary>
/// To Get Deeper Properties such as Role.Name Expressions
/// </summary>
private static Expression GetDeepPropertyExpression(Expression initialInstance, string property)
{
Expression result = null;
foreach (string propertyName in property.Split('.'))
{
Expression instance = result ?? initialInstance;
result = Expression.Property(instance, propertyName);
}
return result;
}
Thanks to NinjaNye , I have borrowed BuildOrExpression which resolved my problem
Here is the solution
public static Expression<Func<T, bool>> FilterKey<T>(string filterText, params string[] properties)
{
ParameterExpression parameter = Expression.Parameter(typeof (T));
Expression[] propertyExpressions = properties.Select(
x => !string.IsNullOrEmpty(x) ? GetDeepPropertyExpression(parameter, x) : null).ToArray();
Expression like= propertyExpressions.Select(expression => Expression.Call(expression, typeof (string).GetMethod("ToLower", Type.EmptyTypes))).Select(toLower => Expression.Call(toLower, typeof (string).GetMethod("Contains"), Expression.Constant(filterText.ToLower()))).Aggregate<MethodCallExpression, Expression>(null, (current, ex) => BuildOrExpression(current, ex));
return Expression.Lambda<Func<T, bool>>(like, parameter);
}
private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd)
{
if (existingExpression == null)
{
return expressionToAdd;
}
//Build 'OR' expression for each property
return Expression.OrElse(existingExpression, expressionToAdd);
}
private static Expression GetDeepPropertyExpression(Expression initialInstance, string property)
{
Expression result = null;
foreach (string propertyName in property.Split('.'))
{
Expression instance = result ?? initialInstance;
result = Expression.Property(instance, propertyName);
}
return result;
}
这篇关于使用表达式的LINQ过滤器实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!