我有一组这种形式的搜索条件:
member | value | operator
--------+---------+---------
height | 10 | >
height | 2 | <
name | Carl | ==
我想查询所有符合这些条件的对象。
现在,我正在通过:
- 为每一个建立一个表达式 的标准
- 使用“或”连接每个表达式 表达
- 构建一个lambda 表达式包含 连接表达式
- 将 lambda 表达式传递给 IQueryable<>.Where() 方法
您知道使用连续 OR 动态过滤 IQueryable 集合的最简单方法吗?
奖金我们的解决方案:
基于 IlyaBuiluk solution @ CodeProject
// The structure used by the new extension method
public struct SearchCriteria
{
public string Column;
public object Value;
public WhereOperation Operation;
}
// How to convert the rules structure to the search criteria structure
var searchCriterias = grid.Where.rules.Select(Rule => new SearchCriteria
{
Column = Rule.field,
Operation =
(WhereOperation)
StringEnum.Parse(
typeof (WhereOperation),
Rule.op),
Value = Rule.data
}).ToArray();
// Usage:
query = query.WhereOr(searchCriterias);
// Implementation
public static IQueryable<T> WhereOr<T>( this IQueryable<T> Query, SearchCriteria [ ] Criterias )
{
if( Criterias.Count( ) == 0 )
return Query;
LambdaExpression lambda;
Expression resultCondition = null;
// Create a member expression pointing to given column
ParameterExpression parameter = Expression.Parameter( Query.ElementType, "p" );
foreach( var searchCriteria in Criterias )
{
if( string.IsNullOrEmpty( searchCriteria.Column ) )
continue;
MemberExpression memberAccess = null;
foreach( var property in searchCriteria.Column.Split( '.' ) )
memberAccess = MemberExpression.Property
( memberAccess ?? ( parameter as Expression ), property );
// Change the type of the parameter 'value'. it is necessary for comparisons (specially for booleans)
ConstantExpression filter = Expression.Constant
(
Convert.ChangeType( searchCriteria.Value, memberAccess.Type )
);
//switch operation
Expression condition = null;
switch( searchCriteria.Operation )
{
//equal ==
case WhereOperation.Equal:
condition = Expression.Equal( memberAccess, filter );
break;
//not equal !=
case WhereOperation.NotEqual:
condition = Expression.NotEqual( memberAccess, filter );
break;
// Greater
case WhereOperation.Greater:
condition = Expression.GreaterThan( memberAccess, filter );
break;
// Greater or equal
case WhereOperation.GreaterOrEqual:
condition = Expression.GreaterThanOrEqual( memberAccess, filter );
break;
// Less
case WhereOperation.Less:
condition = Expression.LessThan( memberAccess, filter );
break;
// Less or equal
case WhereOperation.LessEqual:
condition = Expression.LessThanOrEqual( memberAccess, filter );
break;
//string.Contains()
case WhereOperation.Contains:
condition = Expression.Call( memberAccess,
typeof( string ).GetMethod( "Contains" ),
Expression.Constant( searchCriteria.Value ) );
break;
default:
continue;
}
resultCondition = resultCondition != null ? Expression.Or( resultCondition, condition ): condition;
}
lambda = Expression.Lambda( resultCondition, parameter );
MethodCallExpression result = Expression.Call(
typeof( Queryable ), "Where",
new [ ] { Query.ElementType },
Query.Expression,
lambda );
return Query.Provider.CreateQuery<T>( result );
}
最佳答案
如果您有一组固定的运算符和一组固定的成员,那么您几乎可以在不直接处理表达式树的情况下编写它。这个想法是为各种代码片段创建简单的 lambda 表达式(例如 Expression<Func<Entity, string>>
用于读取成员的属性和类似的运算符),然后将它们组合起来构建一个表达式树。我 described the solution here .唯一的问题是 C# 不直接支持组合表达式,因此您需要进行一些预处理(请参阅有关“可扩展实用程序”的部分)。
然后您可以将基本功能存储在字典中,并根据用户选择的内容选择正确的功能(或它们的组合)。例如:
NorthwindDataContext db = new NorthwindDataContext();
// A query that tests whether a property
// (specified by 'selector' matches a string value
var queryBuilder = Linq.Func
((Expression<Func<Customer, string>> selector, string val) =>
from c in db.Customers.ToExpandable()
where selector.Expand(c).IndexOf(val) != -1
select c);
// Dictionary with supported members...
var dict = new Dictionary<string, Expression<Func<Customer, string>>>
{ { "CompanyName", c => c.CompanyName },
{ "Country", c => c.Country },
{ "ContactName", c => c.ContactName } };
// Ask user for a property name & value and Build the query
string field = Console.ReadLine();
string value = Console.ReadLine();
var q = queryBuilder(dict[field], value);
本文还包含一个动态组合 OR 或 AND 条件的示例。我有一段时间没有更新代码,所以它需要一些工作,但我相信 LINQ KIT项目也包含这个想法的一个版本。
关于c# - IQueryable:动态创建 OR 过滤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3712803/