在使用Entity Framework做數據查詢的時候,查詢條件往往不是固定的,需要動態查詢。可以通過動態構建Lamda表達式來實現動態查詢。 Lamda表達式 使用Lamda表達式可以很方便的按條件過濾數據。Entity Framework也是將Lamda表達式轉換成對應的SQL語句執行。 ...
在使用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