• 动态构建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

  • 相关阅读:
    Java知识点梳理——集合
    Java知识点梳理——装箱和拆箱
    Shiro RememberMe 1.2.4 反序列化漏洞详细复现
    哈希长度拓展攻击之De1CTF
    Discuz! ML RCE漏洞 getshell 复现
    Redis基于主从复制的RCE 4.x/5.x 复现
    WebLogic反序列化漏洞(CVE-2019-2725补丁绕过)
    【实战2】记一次获取远程桌面历程
    远程桌面远程代码执行漏洞(CVE-2019-0708)Poc
    【实战1】记一次提至administrator权限历程
  • 原文地址:https://www.cnblogs.com/seriawei/p/entity-framework-dynamic-search.html
Copyright © 2020-2023  润新知