我有一套这种形式的搜索标准:
member | value | operator
--------+---------+---------
height | 10 | >
height | 2 | <
name | Carl | ==
我想查询所有符合这些标准的对象。
现在,我是这样做的:
您是否知道使用连续OR过滤dinamycally 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 );
}
答案 0 :(得分:3)
如果你有一组固定的运算符和一组固定的成员,那么你几乎不用直接处理表达式树就可以写出来。我们的想法是为各种代码创建简单的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项目也包含了这个想法的一个版本。
答案 1 :(得分:-1)
在性能和易于实现方面,与使用动态查询库相比,这是一种更好的方法吗?我相信这样你可以更好地控制表达式树的SQL输出。