动态构建Lambda表达式实现EF动态查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态构建Lambda表达式实现EF动态查询相关的知识,希望对你有一定的参考价值。

在使用Entity Framework做数据查询的时候,查询条件往往不是固定的,需要动态查询。可以通过动态构建Lamda表达式来实现动态查询。

Lamda表达式

使用Lamda表达式可以很方便的按条件过滤数据。Entity Framework也是将Lamda表达式转换成对应的SQL语句执行。

比如下列代码,输出年龄大于1的人的名字:

namespace ConsoleApp

    public class Person
    
        public string Name  get; set; 
        public int Age  get; set; 
    
    class MyDbContext : DbContext
    
        public DbSet<Person> People  get; set; 
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        
            optionsBuilder.UseSqlServer("Server=(local);Database=TestDB;User Id=sa;Password=sa;");
        
    

    class Program
    
        static void Main(string[] args)
        
            MyDbContext dbContext = new MyDbContext();

            foreach (var item in dbContext.People.Where(m => m.Age > 1))
            
                Console.WriteLine(item.Name);
            
        
    

peoples.Where(m => m.Age > 1)这个在代码里面写死了,如果要换条件就一定要改代码。

Expression

先看一下Where里面是什么,Where里面是表达式的主体,分为参数m,左边参数m的属性和右边的值,通过中间的大于运算符进行比较运算。所以我们在构建表达式的时候,也需要构建这四个部分:

  • 参数
  • 参数的属性
  • 运算符

参数

参数有类型和名字:

Type type= typeof(Person);
var parameter = Expression.Parameter(type, "m");

属性

我们需要知道属性的名称和类型,可通过反射来得到对应的类型并和刚刚的参数关联起来:

PropertyInfo property = type.GetProperty("Age");
Expression expProperty = Expression.Property(parameter, property.Name);

我们还需构建一个值的表达式:

Expression<Func<object>> valueLamda = () => 1;
Expression expValue = Expression.Convert(valueLamda.Body, property.PropertyType);

因为值委托的返回类型是object,所以需要使用Expression.Convert来转换成正确的类型。

如果值是简单类型,如int, string等,也可以直接使用Expression.Constant,简单一些:

Expression expValue = Expression.Constant(1);

运算符

现在已经有了属性表达式,值表达式,接下来就是要使用运算符表达式把它们连接起来:

Expression expression = Expression.GreaterThan(expProperty, expValue);

将表达式转换成对应的类型即可以使用了: 

Expression<Func<Person, bool>> filter = ((Expression<Func<Person, bool>>)Expression.Lambda(expression, parameter));
foreach (var item in dbContext.People.Where(filter))

    Console.WriteLine(item.Name);

下面是完整代码

namespace ConsoleApp

    public class Person
    
        public string Name  get; set; 
        public int Age  get; set; 
    
    class MyDbContext : DbContext
    
        public DbSet<Person> People  get; set; 
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        
            optionsBuilder.UseSqlServer("Server=(local);Database=TestDB;User Id=sa;Password=sa;");
        
    

    class Program
    
        static void Main(string[] args)
        
            MyDbContext dbContext = new MyDbContext();

            Type type = typeof(Person);
            var parameter = Expression.Parameter(type, "m");

            PropertyInfo property = type.GetProperty("Age");
            Expression expProperty = Expression.Property(parameter, property.Name);

            Expression<Func<object>> valueLamda = () => 1;
            Expression expValue = Expression.Convert(valueLamda.Body, property.PropertyType);

            Expression expression = Expression.GreaterThan(expProperty, expValue);
            Expression<Func<Person, bool>> filter = ((Expression<Func<Person, bool>>)Expression.Lambda(expression, parameter));
            foreach (var item in dbContext.People.Where(filter))
            
                Console.WriteLine(item.Name);
            
        
    

这样就可以通过动态传入属性名和值来进行动态查询了。

封装和使用

我们做了一些简单的封装,更方便使用,代码:

https://github.com/SeriaWei/ZKEACMS/blob/master/src/EasyFrameWork/LINQ/Query.cs

使用QueryCollection来添加条件,最后转成表达式:

static void Main(string[] args)

    MyDbContext dbContext = new MyDbContext();

    QueryCollection queries = new QueryCollection();
    queries.Add(new Query  Name = "Age", Operator = Query.Operators.GreaterThan, Value = 1 );

    foreach (var item in dbContext.People.Where(queries.AsExpression<Person>()))
    
        Console.WriteLine(item.Name);
    

原文地址:http://www.zkea.net/codesnippet/detail/entity-framework-dynamic-search.html

以上是关于动态构建Lambda表达式实现EF动态查询的主要内容,如果未能解决你的问题,请参考以下文章

Lambda表达式树解析(下)

c# ef框架的删除的lamda表达式怎么封装

基于Expression Lambda表达式树的通用复杂动态查询构建器——《构思篇二》已开源

EF Core 2.0 中的动态访问表

根据表达式树动态生成Lambda表达式

有没有办法在 lambda 表达式树中使用“动态”?