c# 动态构建LINQ查询表达式

 更新时间:2020年11月27日 16:19:08   作者:精致码农 • 王亮  
这篇文章主要介绍了c# 如何动态构建LINQ查询表达式,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下

作者:精致码农

出处:http://cnblogs.com/willick

联系:liam.wang@live.com

最近工作中遇到一个这样的需求:在某个列表查询功能中,可以选择某个数字列(如商品单价、当天销售额、当月销售额等),再选择 小于或等于大于或等于 ,再填写一个待比较的数值,对数据进行查询过滤。

如果只有一两个这样的数字列,那么使用 Entity Framework Core 可以这么写 LINQ 查询:

public Task<List<Product>> GetProductsAsync(string propertyToFilter, MathOperator mathOperator, decimal value)
{
  var query = _context.Products.AsNoTracking();

  query = propertyToFilter switch
  {
    "Amount1" when mathOperator == MathOperator.LessThanOrEqual => query.Where(x => x.Amount1 <= value),
    "Amount1" when mathOperator == MathOperator.GreaterThanOrEqual => query.Where(x => x.Amount1 >= value),

    "Amount2" when mathOperator == MathOperator.LessThanOrEqual => query.Where(x => x.Amount2 <= value),
    "Amount2" when mathOperator == MathOperator.GreaterThanOrEqual => query.Where(x => x.Amount2 >= value),

    _ => throw new ArgumentException($"不支持 {propertyToFilter} 列作为数字列查询", nameof(propertyToFilter))
  };

  return query.ToListAsync();
}

如果固定只有一两个数字列且将来也不会再扩展,这样写简单粗暴,也没什么问题。

但如果有几十个数字列,这样使用 swith 模式匹配的写法就太恐怖了,代码大量重复。很自然地,我们得想办法根据属性名动态创建 Where 方法的参数。它的参数类型是:Expression<Func<T, bool>>,是一个表达式参数。

要知道如何动态创建一个类似 Expression<Func<T, bool>> 类型的表达式实例,就要知道如何拆解表达式树。

对于本示例,以 x => x.Amount1 <= value 表达式实例为例,它的表达式树是这样的:

然后我们可以按照此表达式树结构来构建我们的 LINQ 表达式:

public Task<List<Product>> GetProductsAsyncV2(string propertyToFilter, MathOperator mathOperator, decimal value)
{
  var query = _context.Products.AsNoTracking();

  var paramExp = Expression.Parameter(typeof(Product));
  var memberExp = Expression.PropertyOrField(paramExp, propertyToFilter);
  var valueExp = Expression.Constant(value);
  var compareExp = mathOperator == MathOperator.LessThanOrEqual ?
    Expression.LessThanOrEqual(memberExp, valueExp) :
    Expression.GreaterThanOrEqual(memberExp, valueExp);
  var lambda = Expression.Lambda<Func<Product, bool>>(compareExp, paramExp);

  return query.Where(lambda).ToListAsync();
}

每个 Expression.XXX 静态方法返回的都是一个以 Expression 为基类的实例,代表一个表达式。不同的表达式又可以组成一个新的表达式,直到得到我们需要的 Lambda 表达式。这样就形成了一种树形结构,我们称为表达式树。知道如何把一个最终的查询表达式拆解成表达式树,我们就容易动态构建此查询表达式。

得到一个表达式后,我们还可以动态编译并调用该表达式,比如上面示例得到的 lambda 变量,是一个Expression<Func<Product, bool>> 类型,调用其 Compile 方法,可以得到 Func<Product, bool> 类型的委托。

...

var toTestProduct = new Product { Amount1 = 100, Amount2 = 200 };

Func<Product, bool> func = lambda.Compile();
var result = func(toTestProduct);

Console.WriteLine($"The product's {propertyToFilter} is to {mathOperator} {value}.");

// Output: The product's Amount1 is LessThanOrEqual to 150.

你可以通过研究 Expression 类来了解更多动态构建表达式的方法。

动态构建 LINQ 表达式对于不能在编译时建立查询,只能在运行时建立查询的场景很有用。但它的缺点也很明显,不易维护、不易阅读、不易调试。如果最终的表达式执行出错,很难通过调试来发现具体是构建中的那一步写错了,只能凭自己的理解和经验查找错误。所以,如非必须,一般不推荐动态构建 LINQ 查询表达式。

以上就是c# 动态构建LINQ查询表达式的详细内容,更多关于c# LINQ查询表达式的资料请关注脚本之家其它相关文章!

相关文章

  • C#/VB.NET实现HTML转为XML的示例代码

    C#/VB.NET实现HTML转为XML的示例代码

    可扩展标记语言(XML)文件是一种标准的文本文件,它使用特定的标记来描述文档的结构以及其他特性。本文将利用C#实现HTML转为XML,需要的可以参考一下
    2022-06-06
  • Unity 从UI中拖拽对象放置并拖动效果 附demo

    Unity 从UI中拖拽对象放置并拖动效果 附demo

    最近新接了个需求,要求模拟场景并生成3D对象,对象可以跟随鼠标移动效果,今天小编把我实现的demo分享到脚本之家平台,对Unity UI拖拽相关知识感兴趣的朋友跟随小编一起学习吧
    2021-05-05
  • 详解C#通过反射获取对象的几种方式比较

    详解C#通过反射获取对象的几种方式比较

    本文主要介绍了C#通过反射获取对象的几种方式比较,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06
  • C# 当前系统时间获取及时间格式详解

    C# 当前系统时间获取及时间格式详解

    这篇文章主要介绍了C# 当前系统时间获取及时间格式详解的相关资料,这里提供代码实例,帮助大家学习参考,需要的朋友可以参考下
    2016-12-12
  • C#之HttpClient设置cookies的两种方式

    C#之HttpClient设置cookies的两种方式

    这篇文章主要介绍了C#之HttpClient设置cookies的两种方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 深入浅析C#中的var和dynamic

    深入浅析C#中的var和dynamic

    这篇文章给大家介绍了C#中的var和dynamic的相关知识,var和dynamic的本质区别是类型判断的时间不同,前者是编译时,后者是运行时。具体内容详情大家通过本文学习下吧
    2018-05-05
  • C#中互操作性简介

    C#中互操作性简介

    这篇文章主要介绍了C#中互操作性的相关资料,文中讲解非常细致,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • C#中IEnumerable、ICollection、IList、List之间的区别

    C#中IEnumerable、ICollection、IList、List之间的区别

    IEnumerable、ICollection、IList、List之间的区别,本文分别分析了它的实现源码,从而总结出了它们之间的关系和不同之处。对C# IEnumerable、ICollection、IList、List相关知识,感兴趣的朋友一起看看吧
    2021-07-07
  • 深入讲解C#编程中嵌套类型和匿名类型的定义与使用

    深入讲解C#编程中嵌套类型和匿名类型的定义与使用

    这篇文章主要介绍了C#编程中嵌套类型和匿名类型的定义与使用,包括在SQL语句中使用匿名类型的方法,需要的朋友可以参考下
    2016-01-01
  • linux操作系统安装MONO执行C#程序的详解步骤

    linux操作系统安装MONO执行C#程序的详解步骤

    这篇文章主要介绍了linux操作系统安装MONO执行C#程序详解步骤,有需要的可以参考一下
    2013-12-12

最新评论