動態構建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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM