C# IQueryable:动态创建或筛选

C# IQueryable:动态创建或筛选,c#,linq,linq-to-entities,expression-trees,iqueryable,C#,Linq,Linq To Entities,Expression Trees,Iqueryable,我有一套如下形式的搜索标准: member | value | operator --------+---------+--------- height | 10 | > height | 2 | < name | Carl | == 成员|值|运算符 --------+---------+--------- 高度| 10 |> 高度| 2 |< 姓名|卡尔|== 我想查询所有符合这些标准的对象 现在,我通

我有一套如下形式的搜索标准:

 member  |  value  |  operator
 --------+---------+---------
 height  |   10    |    >
 height  |    2    |    < 
 name    |  Carl   |   ==
成员|值|运算符
--------+---------+---------
高度| 10 |>
高度| 2 |<
姓名|卡尔|==
我想查询所有符合这些标准的对象

现在,我通过以下方式来实现:

  • 为每个表达式构建一个表达式 标准
  • 使用“或”连接每个表达式 表情
  • 建立一个lambda 包含 串联表达式
  • 将lambda表达式传递给IQueryable.Where()方法
你知道一个最简单的方法来过滤一个IQueryable集合吗


奖励我们的解决方案: 基于

//新扩展方法使用的结构
公共结构搜索条件
{
公共字符串列;
公共客体价值;
公共业务;
}
//如何将规则结构转换为搜索条件结构
var searchCriterias=grid.Where.rules.Select(Rule=>newsearchcriterias
{
Column=Rule.field,
操作=
(操作)
StringEnum.Parse(
类型(操作),
规则(op),,
值=Rule.data
}).ToArray();
//用法:
query=query.where(searchCriterias);
//实施
公共静态IQueryable where(此IQueryable查询,SearchCriterias[]标准)
{
if(Criterias.Count()==0)
返回查询;
lambdaexpressionlambda;
表达式resultCondition=null;
//创建指向给定列的成员表达式
ParameterExpression参数=Expression.parameter(Query.ElementType,“p”);
foreach(标准中的var搜索标准)
{
if(string.IsNullOrEmpty(searchCriteria.Column))
继续;
MemberExpression memberAccess=null;
foreach(searchCriteria.Column.Split('.')中的var属性)
memberAccess=MemberExpression.Property
(memberAccess??(参数作为表达式),属性);
//更改参数“value”的类型。这是比较所必需的(特别是布尔型)
ConstantPression过滤器=表达式常数
(
Convert.ChangeType(searchCriteria.Value,memberAccess.Type)
);
//开关操作
表达式条件=null;
开关(searchCriteria.Operation)
{
//相等的==
操作情况。等于:
条件=表达式.Equal(memberAccess,筛选器);
打破
//不平等=
案例WhereOperation.NotEqual:
条件=Expression.NotEqual(memberAccess,filter);
打破
//更大的
案例操作。更大:
条件=表达式.GreaterThan(memberAccess,筛选器);
打破
//大于或等于
如果Operation.GreaterEqual:
条件=表达式.GreaterThanOrEqual(成员访问,筛选器);
打破
//少
案例操作。减去:
条件=Expression.LessThan(memberAccess,filter);
打破
//少于或等于
案例WhereOperation.LessEqual:
条件=表达式.lessthanRequal(memberAccess,筛选器);
打破
//string.Contains()
案例操作。包含:
条件=表达式.Call(memberAccess,
typeof(string).GetMethod(“包含”),
常量(searchCriteria.Value));
打破
违约:
继续;
}
resultCondition=resultCondition!=null?表达式。或(resultCondition,condition):条件;
}
lambda=Expression.lambda(结果条件,参数);
MethodCallExpression结果=表达式.Call(
typeof(可查询),“Where”,
新[]{Query.ElementType},
Query.Expression,
lambda);
返回Query.Provider.CreateQueryT(结果);
}

如果您有一组固定的运算符和一组固定的成员,那么您几乎可以编写它,而无需直接处理表达式树。其思想是为各种代码段创建简单的lambda表达式(例如,用于读取成员属性的
表达式
,以及用于运算符的类似表达式),然后组合它们以构建表达式树。我唯一的问题是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);
NorthwindDataContext db=新的NorthwindDataContext();
//一种查询,用于测试属性
//(由“选择器”指定与字符串值匹配
var queryBuilder=Linq.Func
((表达式选择器,字符串val)=>
从db.Customers.ToExpandable()中的c
其中selector.Expand(c).IndexOf(val)!=-1
选择c);
//支持成员的字典。。。
var dict=新字典
{{“CompanyName”,c=>c.CompanyName},
{“国家”,c=>c.Country},
{“ContactName”,c=>c.ContactName};
//请用户输入属性名称和值,然后生成查询
字符串字段=Console.ReadLine();
字符串值=Console.ReadLine();
var q=查询生成器(dict[字段],值);
本文还包含一个动态组合OR条件的示例。我有一段时间没有更新代码,因此需要做一些工作,但我相信project也包含了这个想法的一个版本。

在性能方面
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);