前言
因為久久要寫一個泛型的Expression Tree時,都需要找滿久的資料,以及花不少時間看懂微軟的範例程式,所以乾脆自己紀錄一下。
需求是這樣的,有一個GenericRepository
這是要搜尋的資料表轉換到程式碼的類別Product,現在希望能夠取得特定時段更新的商品資料。換句話說,就是利用Product_UpdateTime來篩選資料
public partial class Product
{
public System.Guid Product_ID { get; set; }
public string Product_Name { get; set; }
public decimal Product_Price { get; set; }
public System.DateTime Product_UpdateTime { get; set; }
}
如同前面所說的,需要創建一個Expression Tree來表示條件式。假設,我們希望能夠取出在2015/12/28這一天有更新的資料,先將平常使用的Lambda寫出來
p => p.Product_UpdateTime >= new DateTime(2015, 12, 28, 0, 0, 0) && p.Product_Update < new DateTime(2015, 12, 29, 0, 0, 0)
這就是我們想要的Lambda條件式,接下來就照著這一個條件式來寫Expression Tree。主要可以分為幾個步驟
-
創建p
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
-
Product_UpdateTime >= or < DateTime
//// p.Product_UpdateTime() >= new DateTime(2015, 12, 28, 0, 0, 0) Expression left = Expression.Property(pe, lastUpdateTimeName); Expression right = Expression.Constant(new DateTime(2015, 12, 28, 0, 0, 0), typeof(DateTime)); Expression e1 = Expression.GreaterThanOrEqual(left, right); //// p.Product_UpdateTime < new DateTime(2015, 12, 29, 0, 0, 0) left = Expression.Property(pe, lastUpdateTimeName); right = Expression.Constant(new DateTime(2015, 12, 29, 0, 0, 0), typeof(DateTime)); Expression e2 = Expression.LessThan(left, right);
-
兩個運算式組合,轉Lambda
//// p.Product_UpdateTime() >= '2015/12/28' && p.Product_UpdateTime < '2015/12/29' Expression predicateBody = Expression.AndAlso(e1, e2); var predicate = Expression.Lambda<Func<T, bool>>(predicateBody, pe);
需要注意的地方應該只有,Expression right的部分,型別需要注意。另外還有一個需要特別注意的地方是e1的部分,因為e1是組合left, Right,所以需要注意這兩個參數型別是否有實作比較的方式,也就是GreaterThanOrEqual這一個method的部分。
底下是完整的method程式碼
public class GenericRepository<T> : IRepository<T> where T : class, new()
{
private TestDBEntities _testDbContext;
private IDbSet<T> _dbSet;
public GenericRepository(TestDBEntities dbContext)
{
this._testDbContext = dbContext;
this._dbSet = this._testDbContext.Set<T>();
}
public List<T> GetDataByUpdateTime(DateTime startDataTime, DateTime endDataTime)
{
var objs = new List<T>();
var tName = typeof (T).Name;
var lastUpdateTimeName = string.Format("{0}_UpdateTime", tName);
// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
// ***** Where(p => p.Product_UpdateTime() >= startDataTime && p.Product_UpdateTime < endDataTime) *****
// Create an expression tree that represents the expression 'p.Product_UpdateTime() >= startDataTime'.
Expression left = Expression.Property(pe, lastUpdateTimeName);
Expression right = Expression.Constant(startDataTime, typeof(DateTime));
Expression e1 = Expression.GreaterThanOrEqual(left, right);
// Create an expression tree that represents the expression 'p.Product_UpdateTime < endDataTime'.
left = Expression.Property(pe, lastUpdateTimeName);
right = Expression.Constant(endDataTime, typeof(DateTime));
Expression e2 = Expression.LessThan(left, right);
// Combine the expression trees to create an expression tree that represents the
// expression '(p.Product_UpdateTime() >= startDataTime && p.Product_UpdateTime < DendDataTime)'.
Expression predicateBody = Expression.AndAlso(e1, e2);
var predicate = Expression.Lambda<Func<T, bool>>(predicateBody, pe);
objs = this._dbSet.Where(predicate).ToList();
return objs;
}
}
參考資料:
How to: Use Expression Trees to Build Dynamic Queries (C# and Visual Basic)
免責聲明:
"文章一定有好壞,文章內容有對有錯,使用前應詳閱公開說明書"