C# Linq、Lambda表达式树动态构建、合并条件扩展方法
前言
日常开发时,使用Linq和EF经常会在存在多条件查询,或者说动态条件查询时,便存在合并表达式树的情况。基于这种情况结合一些资料,写了个扩展类,代码如下:
代码实现
/// <summary>
/// Linq表达式扩展方法
/// </summary>
public static class PredicateExtensions
{
/// <summary>
/// 以And合并单个表达式
/// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
/// </summary>
public static Expression<Func<T, bool>> MergeAnd<T>(this Expression<Func<T, bool>> leftExpress, Expression<Func<T, bool>> rightExpress)
{
//声明传递参数(也就是表达式树里面的参数别名s)
ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
//统一管理参数,保证参数一致,否则会报错
var visitor = new PredicateExpressionVisitor(parameter);
//表达式树内容
Expression left = visitor.Visit(leftExpress.Body);
Expression right = visitor.Visit(rightExpress.Body);
//合并表达式
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
}
/// <summary>
/// 以And合并多个表达式
/// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
/// </summary>
public static Expression<Func<T, bool>> MergeAnd<T>(this Expression<Func<T, bool>> express, params Expression<Func<T, bool>>[] arrayExpress)
{
if (!arrayExpress?.Any() ?? true) return express;
//声明传递参数(也就是表达式树里面的参数别名s)
ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
//统一管理参数,保证参数一致,否则会报错
var visitor = new PredicateExpressionVisitor(parameter);
Expression<Func<T, bool>> result = null;
//合并表达式
foreach (var curExpression in arrayExpress)
{
//表达式树内容
Expression left = visitor.Visit(result.Body);
Expression right = visitor.Visit(curExpression.Body);
result = Expression.Lambda<Func<T, bool>>(Expression.AndAlso(left, right), parameter);
}
return result;
}
/// <summary>
/// 以Or合并表达式
/// 此处采用OrElse实现“最短路径”,避免掉额外且不需要的比较运算式
/// </summary>
public static Expression<Func<T, bool>> MergeOr<T>(this Expression<Func<T, bool>> leftExpress, Expression<Func<T, bool>> rightExpress)
{
//声明传递参数(也就是表达式树里面的参数别名s)
ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
//统一管理参数,保证参数一致,否则会报错
var visitor = new PredicateExpressionVisitor(parameter);
//表达式树内容
Expression left = visitor.Visit(leftExpress.Body);
Expression right = visitor.Visit(rightExpress.Body);
//合并表达式
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
}
/// <summary>
/// 以Or合并多个表达式
/// 此处采用AndAlso实现“最短路径”,避免掉额外且不需要的比较运算式
/// </summary>
public static Expression<Func<T, bool>> MergeOr<T>(this Expression<Func<T, bool>> express, params Expression<Func<T, bool>>[] arrayExpress)
{
if (!arrayExpress?.Any() ?? true) return express;
//声明传递参数(也就是表达式树里面的参数别名s)
ParameterExpression parameter = Expression.Parameter(typeof(T), "s");
//统一管理参数,保证参数一致,否则会报错
var visitor = new PredicateExpressionVisitor(parameter);
Expression<Func<T, bool>> result = null;
//合并表达式
foreach (var curExpression in arrayExpress)
{
//表达式树内容
Expression left = visitor.Visit(result.Body);
Expression right = visitor.Visit(curExpression.Body);
result = Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
}
return result;
}
}
public class PredicateExpressionVisitor : ExpressionVisitor
{
public ParameterExpression _parameter { get; set; }
public PredicateExpressionVisitor(ParameterExpression parameter)
{
_parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression p)
{
return _parameter;
}
public override Expression Visit(Expression expression)
{
//Visit会根据VisitParameter()方法返回的Expression进行相关变量替换
return base.Visit(expression);
}
}
使用例子
class Program
{
static void Main(string[] args)
{
var models = new List<JsonData>() { new JsonData() { Id = "001", Name = "One" }, new JsonData() { Id = "002", Name = "Tow" } };
Console.WriteLine($"未处理集合:{string.Join(',', models.Select(o => o.Id))}");
//表达式1
Expression<Func<JsonData, bool>> expression1 = t => t.Id == "001";
//表达式2
Expression<Func<JsonData, bool>> expression2 = t => t.Name == "Tow";
//合并成 t => t.Id=="001" && t.Name=="One"
Expression<Func<JsonData, bool>> allEexpression = expression1.MergeAnd(expression2);
Console.WriteLine(allEexpression.Body.ToString());
Console.WriteLine($"已处理集合(And):{string.Join(',', models.Where(expression1.MergeAnd(expression2).Compile()).Select(o => o.Id))}");
//合并成 t => t.Id=="001" || t.Name=="One"
allEexpression = expression1.MergeOr(expression2);
Console.WriteLine(allEexpression.Body.ToString());
Console.WriteLine($"已处理集合(Or):{string.Join(',', models.Where(allEexpression.Compile()).Select(o => o.Id))}");
Console.ReadKey();
}
}
public class JsonData
{
public string Id { get; set; }
public string Name { get; set; }
}
结果
相关资料
C# Linq、Lambda表达式树动态构建、合并条件扩展方法的更多相关文章
- 通过LINQ表达式树动态构建查询条件
第一种方法: public static class PredicateExtensions { public static Expression<Func<T, bool>> ...
- LINQ to SQL 运行时动态构建查询条件
在进行数据查询时,经常碰到需要动态构建查询条件.使用LINQ实现这个需求可能会比以前拼接SQL语句更麻烦一些.本文介绍了3种运行时动态构建查询条件的方法.本文中的例子最终实现的都是同一个功能,从Nor ...
- C# Lambda表达式详解,及Lambda表达式树的创建
最近由于项目需要,刚刚学完了Action委托和Func<T>委托,发现学完了委托就必须学习lambda表达式,委托和Lambda表达式联合起来,才能充分的体现委托的便利.才能使代码更加简介 ...
- 将简单的lambda表达式树转为对应的sqlwhere条件
1.Lambda的介绍 园中已经有很多关于lambda的介绍了.简单来讲就是vs编译器给我带来的语法糖,本质来讲还是匿名函数.在开发中,lambda给我们带来了很多的简便.关于lambda的演变过程可 ...
- EntityFramework动态多条件查询与Lambda表达式树
在常规的信息系统中, 我们有需要动态多条件查询的情况, 例如UI上有多个选择项可供用户选择多条件查询数据. 那么在.net平台Entity Framework下, 我们用Lambd ...
- 表达式树动态拼接lambda
动态拼接lambda表达式树 前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dappe ...
- 动态拼接lambda表达式树
前言 最近在优化同事写的代码(我们的框架用的是dapperLambda),其中有一个这样很普通的场景——界面上提供了一些查询条件框供用户来进行过滤数据.由于dapperLambda按条件查询时是传入表 ...
- Lambda表达式树构建(上)
概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可 ...
- 追根溯源之Linq与表达式树
一.什么是表达式树? 首先来看下官方定义(以下摘录自巨硬官方文档) 表达式树表示树状数据结构中的代码,其中每个节点都是表达式,例如,方法调用或诸如的二进制操作x < y. 您可以编译 ...
- C#学习笔记(九):LINQ和表达式树
LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...
随机推荐
- VS Qt扩展插件下载地址
使用vs开发qt项目,需要安装qt插件 QT插件下载地址:https://mirrors.ustc.edu.cn/qtproject/official_releases/vsaddin/
- openGauss事务机制中MVCC技术的实现分析
openGauss 事务机制中 MVCC 技术的实现分析 概述 事务 事务是为用户提供的最核心.最具吸引力的数据库功能之一.简单地说,事务是用户定义的一系列数据库操作(如查询.插入.修改或删除等)的集 ...
- 批处理 if的知识点
正文 批处理的if不同于我们在一些常规语言中的if,比如说c或者c# 或者 java等. 如果我们判断两个字符是否相等,我们使用 'a'=='a' 来判断. 但是如果是不相等却不能这样. gtr 大于 ...
- 实训篇-Html-frameset框架集
frameset.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...
- WPF开发随笔收录-查看PDF文件
一.前言 在项目的开发过程中,涉及到查看服务器生成的pdf报告文件的查看,起初的方案是通过spire.pdf这个库来将pdf文件转换成图片,然后在进行查看.但是经常被吐槽预览不清晰,后面上网发现了一个 ...
- locust分布式压测的Step Load及no web模式下的报表自动生成
Running Locust in Step Load ModeIf you want to monitor your service performance with different user ...
- js获取时间差,返回格式为01天02小时03秒
// 获取时间差 返回值格式:01天02小时30秒 export function caclulateDiffTime(start, end): string { start = new Date(s ...
- 一个好的网站logo设计长这样
简介:一个好的网站logo,不仅让用户一眼知道网站品牌传递的信息,还能提高网站专业度和丰富度,增加SEO搜索排名.今天分享下如何设计一款实用的网站logo.阿里云智能logo设计,在线免费体验log ...
- RocketMQ 端云一体化设计与实践
简介:本文首先介绍了端云消息场景一体化的背景,然后重点分析了终端消息场景特点,以及终端消息场景支撑模型,最后对架构和存储内核进行了阐述.我们期望基于 RocketMQ 统一内核一体化支持终端和服务端不 ...
- Serverless Devs 的官网是如何通过 Serverless Devs 部署的
简介: 只有自己吃自己的狗粮,自己做的东西才不"".Serverless Devs 自发展之处到现在,已经经历了几个月的时间,在这几个月,Serverless Devs 的成长是迅 ...