原文地址:http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx

Someone asked a great question on the ADO.NET Entity Framework forums yesterday: how do I compose predicates in LINQ to Entities? I’ll give three answers to the question.

Answer 1: Chaining query operators

Basically, you have some query and you have some predicates you want to apply to that query (“the car is red”, “the car costs less than $10”). If both conditions need to be satisfied, you can just chain together some calls to Where (“the car is red and costs less than $10”):

Expression<Func<Car, bool>> theCarIsRed = c => c.Color == "Red";

Expression<Func<Car, bool>> theCarIsCheap = c => c.Price < 10.0;

IQueryable<Car> carQuery = …;

var query = carQuery.Where(theCarIsRed).Where(theCarIsCheap);

If you’re willing to exceed the $10 budget for cars that are red, you can chain Unions instead (“the car is red or the car costs less than $10”):

var query2 = carQuery.Where(theCarIsRed).Union(carQuery.Where(theCarIsCheap));

This last query has a couple of problems: it’s inefficient (because of the unions) and it eliminates duplicates in the results, something that would not happen if I applied a single predicate.

Answer 2: Build expressions manually

The LINQ Expressions API includes factory methods that allow you to build up the predicate by hand. I can define the conditions (with respect to a “car” parameter) as follows:

ParameterExpression c = Expression.Parameter(typeof(Car), "car");

Expression theCarIsRed = Expression.Equal(Expression.Property(c, "Color"), Expression.Constant("Red"));

Expression theCarIsCheap = Expression.LessThan(Expression.Property(c, "Price"), Expression.Constant(10.0));

Expression<Func<Car, bool>> theCarIsRedOrCheap = Expression.Lambda<Func<Car, bool>>(

Expression.Or(theCarIsRed, theCarIsCheap), c);

var query = carQuery.Where(theCarIsRedOrCheap);

Building queries by hand isn’t very convenient. If you’re already building expressions from scratch, this is a good approach but otherwise I’d suggest something different…

Answer 3: Composing Lambda Expresions

The Albaharis suggest combining bodies of lambda expressions in their C# 3.0 book (a great resource for all things C# and LINQ). This allows you to describe the parts of the expression using the lambda syntax and build an aggregate expression:

Expression<Func<Car, bool>> theCarIsRed = c1 => c1.Color == "Red";

Expression<Func<Car, bool>> theCarIsCheap = c2 => c2.Price < 10.0;

Expression<Func<Car, bool>> theCarIsRedOrCheap = Expression.Lambda<Func<Car, bool>>(

Expression.Or(theCarIsRed.Body, theCarIsCheap.Body), theCarIsRed.Parameters.Single());

var query = carQuery.Where(theCarIsRedOrCheap);

I’m taking the bodies of the two conditions and Oring them in a new lambda expression. There is a subtle problem however: the parameter for the merged expression (c1) is taken from “theCarIsRed”, which leaves us with a dangling parameter (c2) from “theCarIsCheap”. The resulting query is invalid. How can I force “theCarIsCheap” to use the same parameter? The answer is to invoke the expression using the common parameter:

ParameterExpression p = theCarIsRed.Parameters.Single();

Expression<Func<Car, bool>> theCarIsRedOrCheap = Expression.Lambda<Func<Car, bool>>(

Expression.Or(theCarIsRed.Body, Expression.Invoke(theCarIsCheap, p)), p);

Here’s the problem: LINQ to Entities does not support InvocationExpressions. Rather than invoking the expression with c1, I can manually rebind the parameter. Matt Warren’s series of articles on IQueryable providers includes an ExpressionVisitor implementation that makes it easy to rewrite expression trees. If you do any LINQ expression manipulation, this class is a crucial tool. Here’s an implementation of the visitor that rebinds parameters:

public class ParameterRebinder : ExpressionVisitor {

private readonly Dictionary<ParameterExpression, ParameterExpression> map;

public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) {

this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();

}

public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) {

return new ParameterRebinder(map).Visit(exp);

}

protected override Expression VisitParameter(ParameterExpression p) {

ParameterExpression replacement;

if (map.TryGetValue(p, out replacement)) {

p = replacement;

}

return base.VisitParameter(p);

}

}

Now I can write a general utility method to compose lambda expressions without using invoke (I’ll call it Compose), and leverage it to implement EF-friendly And and Or builder methods:

public static class Utility {

public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge) {

// build parameter map (from parameters of second to parameters of first)

var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);

// replace parameters in the second lambda expression with parameters from the first

var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

// apply composition of lambda expression bodies to parameters from the first expression

return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);

}

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {

return first.Compose(second, Expression.And);

}

public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {

return first.Compose(second, Expression.Or);

}

}

To combine lambda expressions, I can write:

Expression<Func<Car, bool>> theCarIsRed = c => c.Color == "Red";

Expression<Func<Car, bool>> theCarIsCheap = c => c.Price < 10.0;

Expression<Func<Car, bool>> theCarIsRedOrCheap = theCarIsRed.Or(theCarIsCheap);

var query = carQuery.Where(theCarIsRedOrCheap);

I’ll use this last answer as an excuse to discuss variations on the visitor pattern in a future post...

转载于:https://www.cnblogs.com/fcsh820/archive/2011/10/25/2224056.html

(转)LINQ to Entities 多条件动态查询相关推荐

  1. WINFORM 多条件动态查询 通用代码的设计与实现

    经常碰到多条件联合查询的问题,以前的习惯认为很简单总会从头开始设计布局代码,往往一个查询面要费上老半天的功夫,而效果也不咋地.     前段时间做了个相对通用的多条件动态查询面,复用起来还是挺方便的, ...

  2. mysql 使用if函数实现多条件动态查询

    简单多条件动态查询 1.条件为NULL时,不起作用 set @iid = NULL; select * FROM t_sys_cpy WHERE IF(@iid is NULL,1=1,ID = @i ...

  3. linq to sql的多条件动态查询(下)

    借助老外写的一个扩展表达式的类,可以把上篇中的代码写得更优雅 这是PredicateBuilder的源文件  public static class PredicateBuilder     ...{ ...

  4. linq to sql 多条件组合查询

    linq to sql 我这里查询tbdesk表内的记录 DeskTypeID和Name是条件     private void bind()     {         using (cpDataC ...

  5. LINQ to Entities 基于方法的查询语法

    1.投影: Select 与 SelectMany SelectMany操作符提供了将多个from子句组合起来的功能,相当于数据库中的多表连接查询,它将每个对象的结果合并成单个序列. 与 select ...

  6. Linq to sql 实现多条件的动态查询(方法一)

    多条件动态查询在开发中太常见了,使用sql语句拼接很容易实现,但是在使用linq 的时候我却觉得很麻烦,思来想去,其实不然,linq 实现多条件动态查询一样可以变的很简单.话不多说,直接上例子,供大家 ...

  7. spring data jpa封装specification实现简单风格的动态查询

    github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...

  8. jpa多表联查动态_jpa多表关联动态查询(自定义sql语句)

    项目中,jpa对于简单的数据库操作很方便,但如果多表关联动态查询时,需要自己去写SQL语句拼接查询条件,以下为本人学习的例子. 类似于这种多条件动态查询: 项目用的是springboot 2.1.0. ...

  9. LINQ to SQL 运行时动态构建查询条件

    原文地址:http://msdn.microsoft.com/zh-cn/dd567295.aspx 在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句 ...

最新文章

  1. Android获取挂载U盘的属性
  2. 第六章---机器学习与数据建模
  3. 腾讯2011.10.15校园招聘会笔试题
  4. mysqldump: Got error: 1449
  5. java性能调优工具--笔记
  6. 如何将MATLAB程序发布为独立的不依赖MATLAB环境可执行的程序包(基于Matlab R2015b版 )
  7. 泽西岛2.9及更高版本中的声明式链接
  8. HTML期末作业-美食点餐网页
  9. 苹果html阅读器,设置Safari 10.0.2阅读器Reader字体
  10. android中当内容超出一页,滚动条滚动到某一个位置的另一个思路
  11. python源码中的学习笔记_第5章_字典
  12. 基于BP神经网络的人口预测
  13. Windows下搭建SVN服务器 - Visual SVN server
  14. UCOSII系统移植详解
  15. 论文阅读:Time2Graph+: Bridging Time Series and Graph Representation Learning via Multiple Attentions
  16. python爬虫之获取谷歌浏览器所有cookie
  17. 6个步骤教你用Python解数独!(含实例代码)
  18. 转:著名的100个管理定律点评10
  19. 解决移动端,wap站,m站适配方案整理
  20. [其他咚咚]Twins的专辑列表

热门文章

  1. 【深度学习笔记】零基础入门深度学习必备知识
  2. Windows环境下配置环境变量
  3. 怎么预约鸿蒙系统,华为鸿蒙2.0系统-鸿蒙2.0系统预约-艾艾软件园
  4. 武汉网络推广介绍如何通过简化标题来提升主关键词排名?
  5. 浅析优化网站导航设计的几种常用方法
  6. 量子计算机物理学,百年的超越:量子物理学与量子计算机
  7. linux oracle查询乱码问题,Linux环境Oracle显示乱码的解决方法
  8. 安装python38_debian8安装python3.7
  9. 逻辑回归阈值_逻辑回归or线性回归,傻傻分不清楚
  10. 计算机绘画教案风车,中班美术教案《风车》