热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(转)LINQtoEntities多条件动态查询

原文地址:http:blogs.msdn.combmeekarchive20080502linq-to-entities-combining-predicates.a

原文地址: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 &#61; c &#61;> c.Color &#61;&#61; "Red";

Expression<Func<Car, bool>> theCarIsCheap &#61; c &#61;> c.Price <10.0;

IQueryable<Car> carQuery &#61; ;

var query &#61; 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 &#61; 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 &#61; Expression.Parameter(typeof(Car), "car");

Expression theCarIsRed &#61; Expression.Equal(Expression.Property(c, "Color"), Expression.Constant("Red"));

Expression theCarIsCheap &#61; Expression.LessThan(Expression.Property(c, "Price"), Expression.Constant(10.0));

Expression<Func<Car, bool>> theCarIsRedOrCheap &#61; Expression.Lambda<Func<Car, bool>>(

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

var query &#61; 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 &#61; c1 &#61;> c1.Color &#61;&#61; "Red";

Expression<Func<Car, bool>> theCarIsCheap &#61; c2 &#61;> c2.Price <10.0;

Expression<Func<Car, bool>> theCarIsRedOrCheap &#61; Expression.Lambda<Func<Car, bool>>(

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

var query &#61; 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 &#61; theCarIsRed.Parameters.Single();

Expression<Func<Car, bool>> theCarIsRedOrCheap &#61; 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 &#61; 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 &#61; 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 Compose(this Expression first, Expression second, Func<Expression, Expression, Expression> merge) {

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

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

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

        var secondBody &#61; ParameterRebinder.ReplaceParameters(map, second.Body);

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

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

    }

    public static Expression<Funcbool>> And(this Expression<Funcbool>> first, Expression<Funcbool>> second) {

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

    }

    public static Expression<Funcbool>> Or(this Expression<Funcbool>> first, Expression<Funcbool>> second) {

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

    }

}

To combine lambda expressions, I can write:

Expression<Func<Car, bool>> theCarIsRed &#61; c &#61;> c.Color &#61;&#61; "Red";

Expression<Func<Car, bool>> theCarIsCheap &#61; c &#61;> c.Price <10.0;

Expression<Func<Car, bool>> theCarIsRedOrCheap &#61; theCarIsRed.Or(theCarIsCheap);

var query &#61; 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


推荐阅读
  • 在 Kubernetes 中,Pod 的调度通常由集群的自动调度策略决定,这些策略主要关注资源充足性和负载均衡。然而,在某些场景下,用户可能需要更精细地控制 Pod 的调度行为,例如将特定的服务(如 GitLab)部署到特定节点上,以提高性能或满足特定需求。本文深入解析了 Kubernetes 的亲和性调度机制,并探讨了多种优化策略,帮助用户实现更高效、更灵活的资源管理。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • Python 实战:异步爬虫(协程技术)与分布式爬虫(多进程应用)深入解析
    本文将深入探讨 Python 异步爬虫和分布式爬虫的技术细节,重点介绍协程技术和多进程应用在爬虫开发中的实际应用。通过对比多进程和协程的工作原理,帮助读者理解两者在性能和资源利用上的差异,从而在实际项目中做出更合适的选择。文章还将结合具体案例,展示如何高效地实现异步和分布式爬虫,以提升数据抓取的效率和稳定性。 ... [详细]
  • 如何高效启动大数据应用之旅?
    在前一篇文章中,我探讨了大数据的定义及其与数据挖掘的区别。本文将重点介绍如何高效启动大数据应用项目,涵盖关键步骤和最佳实践,帮助读者快速踏上大数据之旅。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • Java Socket 关键参数详解与优化建议
    Java Socket 的 API 虽然被广泛使用,但其关键参数的用途却鲜为人知。本文详细解析了 Java Socket 中的重要参数,如 backlog 参数,它用于控制服务器等待连接请求的队列长度。此外,还探讨了其他参数如 SO_TIMEOUT、SO_REUSEADDR 等的配置方法及其对性能的影响,并提供了优化建议,帮助开发者提升网络通信的稳定性和效率。 ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
  • 如何在C#中配置组合框的背景颜色? ... [详细]
  • 本文探讨了如何在C#应用程序中通过选择ComboBox项从MySQL数据库中检索数据值。具体介绍了在事件处理方法 `comboBox2_SelectedIndexChanged` 中可能出现的常见错误,并提供了详细的解决方案和优化建议,以确保数据能够正确且高效地从数据库中读取并显示在界面上。此外,还讨论了连接字符串的配置、SQL查询语句的编写以及异常处理的最佳实践,帮助开发者避免常见的陷阱并提高代码的健壮性。 ... [详细]
  • 在C#中开发MP3播放器时,我正在考虑如何高效存储元数据以便快速检索。选择合适的数据结构,如字典或数组,对于优化性能至关重要。字典能够提供快速的键值对查找,而数组则在连续存储和遍历方面表现优异。根据具体需求,合理选择数据结构将显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文深入探讨了 hCalendar 微格式在事件与时间、地点相关活动标记中的应用。作为微格式系列文章的第四篇,前文已分别介绍了 rel 属性用于定义链接关系、XFN 微格式增强链接的人际关系描述以及 hCard 微格式对个人和组织信息的描述。本次将重点解析 hCalendar 如何通过结构化数据标记,提高事件信息的可读性和互操作性。 ... [详细]
  • 本文探讨了基于点集估算图像区域的Alpha形状算法在Python中的应用。通过改进传统的Delaunay三角剖分方法,该算法能够生成更加灵活和精确的形状轮廓,避免了单纯使用Delaunay三角剖分时可能出现的过大三角形问题。这种“模糊Delaunay三角剖分”技术不仅提高了形状的准确性,还增强了对复杂图像区域的适应能力。 ... [详细]
  • 如何精通编程语言:全面指南与实用技巧
    如何精通编程语言:全面指南与实用技巧 ... [详细]
  • 本文详细介绍了如何在Java Web服务器上部署音视频服务,并提供了完整的验证流程。以AnyChat为例,这是一款跨平台的音视频解决方案,广泛应用于需要实时音视频交互的项目中。通过具体的部署步骤和测试方法,确保了音视频服务的稳定性和可靠性。 ... [详细]
author-avatar
癫逼
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有