传统的操作数据库方式,筛选数据需要用StringBuilder拼接一大堆的WHERE子句。

在Entity Framework中,代码稍有不慎就会造成巨大性能消耗,如:

using(var db=new MyDbContext())

{

var s= db.Students.ToList().First(s=>s.ID=1200);

}

嘣!进行了全表数据读取!当然一般人也不会犯这种低级的错误,言归正传。

可以简单的这样筛选数据:

using(var db=new MyDbContext())

{

var list =db.Students.AsQueryable();

if(********){list=list.Where(s=>s.ID=1200);}

if(******){list=list.Where(...)}

}

但是有时这种方法不能完成特定需求,如:

using(var db=new MyDbContext())

{

var list =db.Students.AsQueryable();

if(条件1){list=list.Where(s=>s.ID>1200);}

if(条件2){list=list.Where(s=>s.ID<1000);}

}

现在条件1和条件2同时成立,得到的是空结果集而不是ID>1200和ID<1000的结果集。

这只是两个并列简单条件的组合,如果是条件嵌套呢?

下面是假想:

using (var db = new MyDbContext())
            {

Expression<Func<Student, bool>> checkStudent1 = s1 => s1.ID > 1200;
                Expression<Func<Student, bool>> checkStudent2 = s2 => s2.ID < 1000;
                var e =
                    Expression.Lambda<Func<Student, bool>>(
                        Expression.Or(checkStudent1.Body, checkStudent2.Body), checkStudent1.Parameters);
                var result = db.Students.Where(e).ToList();
            }

叫它假想的原因是执行会产生异常”The parameter 's2' was not bound in the specified LINQ to Entities query expression“。

e的内容是{s1 => ((s1.ID > 1200) Or (s2.ID < 1000))},很明显s2这个参数是没有被定义的。

实际上我们一直操作一个Student表,最终我们想要的也是多Lambda表达式合在一起对该Student表的操作。换句话说,s2应该用s1代替。

有人说了,这样:

Expression<Func<Student, bool>> checkStudent1 = s => s.ID > 1200;
                Expression<Func<Student, bool>> checkStudent2 = s => s.ID < 1000;
                var e =
                    Expression.Lambda<Func<Student, bool>>(
                        Expression.Or(checkStudent1.Body, checkStudent2.Body), checkStudent1.Parameters);
                var result = db.Students.Where(e).ToList();

异常:”The parameter 's' was not bound in the specified LINQ to Entities query expression“。

e的内容是{s => ((s.ID > 1200) Or (s.ID < 1000))},现在参数都一样是s了,但其实它们的GUID不同,也就是说它们还是两个不同的参数。

我们需要做的是手工把checkStudent2.Body里面的参数s换成checkStudent1.Body里面的参数s。

ExpressionVisitor可以很好的完成这步操作。拿个别人现成的例子来用:

    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);
}
}

更改后的测试代码:

Expression<Func<Student, bool>> checkStudent1 = s => s.ID > 1200;
                Expression<Func<Student, bool>> checkStudent2 = s => s.ID < 1000;
                
                var body2 =
                    ParameterRebinder.ReplaceParameters(
                       
checkStudent2.Parameters.Select((s,i)=>new{s,f=checkStudent1.Parameters[i]}).ToDictionary(p=>p.s,p=>p.f),
checkStudent2.Body);
                var e =
                    Expression.Lambda<Func<Student, bool>>(
                        Expression.Or(checkStudent1.Body, body2), checkStudent1.Parameters);
                var result = db.Students.Where(e).ToList();

至此表达式顺利拼接完成。当然这样使用还是麻烦,借用别人的扩展类稍微修改一下:

    public static class PredicateBuilder
{ public static Expression<Func<T, bool>> True<T>() { return f => true; }
public static Expression<Func<T, bool>> False<T>() { return f => false; }
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);
}
}

参考:http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx
完美的动态拼接Lambda表达式如下:
using (var db = new MyDbContext())
            {
                var predicate = PredicateBuilder.True<Student>();
                predicate=predicate.And(s => s.ID > 1200);
                predicate=predicate.Or(s => s.ID < 1000);
                var result = db.Students.Where(predicate).ToList();
            }

下面是一个我自己使用的例子,仅供参考:

    using (var db = new SHTrackerDbContext())
{ var predicate = PredicateBuilder.True<Course>();
settings = DecorateSettings(settings); Expression<Func<Course, bool>> checkCourse = c => db.Students.Any(s => s.CourseID == c.ID);
if (!string.IsNullOrEmpty(settings.Quater_Year))
{ checkCourse =
c => db.Students.Any(s => s.CourseID == c.ID && db.Student2CBOs.Any(
s2c => s2c.StudentID == s.ID && s2c.Quater_Year.Equals(settings.Quater_Year)));
}
if (settings.QuaterYearArray != null)
{
checkCourse =
c => db.Students.Any(s => s.CourseID == c.ID && db.Student2CBOs.Any(
s2c =>
s2c.StudentID == s.ID && settings.QuaterYearArray.Any(qy => qy.Equals(s2c.Quater_Year))));
} if (!string.IsNullOrEmpty(settings.DPU_ID))
{
checkCourse =
checkCourse.And(
c => db.Students.Any(s => s.CourseID == c.ID && s.DPU_ID.Equals(settings.DPU_ID)));
}
predicate = predicate.And(checkCourse); if (settings.IsCheckInstructorName)
{
predicate = predicate.And(c => c.InstructorName.Equals(settings.InstructorName));
}
if (!string.IsNullOrEmpty(settings.Term))
{
predicate = predicate.And(c => c.TermDescription.Equals(settings.Term));
}
if (settings.TermArray != null)
{
predicate = predicate.And(c => settings.TermArray.Any(t => t.Equals(c.TermDescription)));
}
if (settings.CourseType != CourseType.All)
{
predicate = predicate.And(c => c.Type == (int) settings.CourseType);
}
var cc =
new CourseCollection(
db.Courses.AsNoTracking()
.Where(predicate)
.OrderByDescending(m => m.ID)
.Skip((pageIndex - 1)*pageSize)
.Take(pageSize)
.ToList(),
db.Courses.AsNoTracking().Where(predicate).Count())
{
PageIndex = pageIndex,
PageSize = pageSize,
Settings = DecorateSettings(settings)
}; return cc;
}

参考:http://blog.csdn.net/leewhoee/article/details/8968023

【转】EntityFramework动态组合Lambda表达式作为数据筛选条件,代替拼接SQL语句的更多相关文章

  1. 动态组合lambda 表达式

    //记录实体集合—动态组合lambda 表达式 Expression<Func<AdEntity, bool>> thirdWhere = p => p.Observer ...

  2. 动态创建Lambda表达式实现高级查询

    需求简介 最近这几天做的东西总算是回归咱的老本行了,给投资管理项目做一个台账的东西,就是类似我们的报表.其 中有一个功能是一个高级查询的需求,在查询条件方面大概有7.8个查询条件.需求就是如果一个条件 ...

  3. easyui datagrid remoteSort的实现 Controllers编写动态的Lambda表达式 IQueryable OrderBy扩展

    EF 结合easy-ui datagrid 实现页面端排序 EF动态编写排序Lambda表达式 1.前端页面 var mainListHeight = $(window).height() - 20; ...

  4. 【mybatis】mybatis执行一个update方法,返回值为1,但是数据库中数据并未更新,粘贴sql语句直接在数据库执行,等待好久报错:Lock wait timeout exceeded; try restarting transaction

    今天使用mybatis和jpa的过程中,发现这样一个问题: mybatis执行一个update方法,返回值为1,但是数据库中数据并未更新,粘贴sql语句直接在数据库执行,等待好久报错:Lock wai ...

  5. 2016/05/13 thinkphp 3.2.2 ① 数据删除及执行原生sql语句 ②表单验证

    [数据删除及执行原生sql语句] delete()  返回受影响的记录条数 $goods -> delete(30);   删除主键值等于30的记录信息 $goods -> delete( ...

  6. java动态拼接sql语句并且执行时给sql语句的参数赋值

    问题 在这里举一个例子,比如我要做一个多条件模糊查询,用户输入的时候有可能输入一个条件,也有可能输入两个条件,这时执行查询的sql语句就不确定了,但可以用动态拼接sql语句来解决这个问题. 解决方法 ...

  7. 动态创建 Lambda 表达式

    首先我们看一个简单 Lambda 表达式的构成. i => i > 5 在这个表达式中,"i" 被称为 Parameter,"i > 5" 是 ...

  8. EntityFramework动态组合多排序字段

    前言:在使用EF当中,肯定会遇到动态查询的需求,建立一个公共调用的动态组合表达式查询也是必不可少的,以下是建立动态组合多排序字段做个记录,供以后调用 1.建立一个结构,用于多个排序字段组合,这个结构体 ...

  9. [2014-12-30]如何动态构造Lambda表达式(动态构造Lambda查询条件表达式)

    声明 本文对Lambda表达式的扩展,示例代码来源于网络. 场景描述 web开发查询功能的时候,如果查询条件比较多,就会遇到动态组合查询条件的情况.在手写sql的情况下,我们一般会根据传入的参数,针对 ...

随机推荐

  1. 立几个flag

    有时候会心血来潮想学一点东西,然后搞别的东西的时候就慢慢忘了.. 这里做个备忘录: 树分块/树上莫队 广义后缀自动机(大概这辈子都不会去学了) 带花树(如果我能学的动那个线代的随机算法就放弃这个) 模 ...

  2. 20145127《java程序设计》第十周学习总结

    Java的网络编程 1.计算机网络概述 (1)路由器和交换机组成了核心的计算机网络,计算机只是这个网络上的节点以及控制等,通过光纤.网线等连接将设备连接起来,从而形成了一张巨大的计算机网络. (2)网 ...

  3. 不是最强大的vimrc

    一直都是使用vim作为我的主要编辑器,它大大提高了我的代码编辑效率.vim的配置高度灵活.插件丰富,恐怕100个人就有99种配置方法,网上关于vim配置的所谓“最强大的vimrc”之类的文章不少,博人 ...

  4. sbt介绍与构建Scala项目

    一.sbt简介 sbt是类似ANT.MAVEN的构建工具,全称为Simple build tool,是Scala事实上的标准构建工具. 主要特性: 原生支持编译Scala代码和与诸多Scala测试框架 ...

  5. Python3基础 父,子类普通方法重名 子类方法覆盖父类方法

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  6. Elasticsearch 原理

    Elasticsearch简介 Elasticsearch是一个基于Apache lucene的实时分布式搜索.具有以下优点: 1.实时处理大规模数据.2.全文检索,能够做到结构化检索和聚合分析.3. ...

  7. UVa 12563 劲歌金曲(0-1背包)

    https://vjudge.net/problem/UVA-12563 题意: 在一定的时间内连续唱歌,最后一首唱11分钟18秒的劲歌金曲,问最多能长多长时间. 思路: 0-1背包问题,背包容量为t ...

  8. UVa 437 巴比伦塔

    https://vjudge.net/problem/UVA-437 这道题和HDU的Monkey and Banana完全一样. #include<iostream> #include& ...

  9. python网络编程之TCP通信实例

    一. server.py import socket host="localhost" port= s=socket.socket(socket.AF_INET,socket.SO ...

  10. python input选择

    例1 import sys #声明字符串数组并初始化 newspaper=['1.北京晚报','2.作家文摘','3.参考消息', \ '4.证券报','5.不需要'] #字符串数组的输出 ): pr ...