Linq Criteria(1)
簡介:
Linq Criteria這是一個動態組合Linq查詢的Library.
這專案是因在一年多前因為Entity Framework的一些參數傳遞上之問題衍生出來所做的Library,不過Library本身是針對Linq所以可以套用於任何Linq衍生出的相關Library.
文章將由使用慢慢進入到設計,這個Library使用的技術比較深入些,也採用了許多現有的Open Source Code.希望介紹後期望有人能夠一起發展讓其更強大.
文章開始:
Linq是.Net 3.0後一項非常重要的技術,Linq解決了以往語言層級在查詢資料上很難有統一模式的問題,而且單就Linq語法而言並不難學習,所以在.Net上使用Linq技術的人越來越多.
但Linq目前還是有幾項缺點尚未克服
1.無法序列化.
2.較複雜的動態Linq目前僅能Linq Expression Tree相關類別來處理,但相當複雜且深奧難理解.
這兩項問題與限制其實都存在一些原因,但若去不考慮某些Linq特性這兩者是可以達成的.而Linq Criteria就是以此撰寫的Library.
會有Linq Criteria的想法是因為早期使用Entity Framework的一些參數傳遞上之問題,而更早之前本身使用的ORM是 NHibernate,在NHibernate有個針對動態查詢的不錯方式就是Criteria機制.
但在EF中不存在類似東西,所以藉由NHibernate Creation的方式做出一組適用於Linq的方式.
撰寫過Linq語法的人應該都寫過下列類似語法
string[] source = new string[]{"aaa", …};
IEnumerable<string> q = from s in source
where s.StartsWith("a")
select s;
而
IEnumerable<string> q = from s in source
where s.StartsWith("a")
select s;
其實有另一個正規寫法如下
IEnumerable<string> q = source.Where(s => s.StartsWith("a")).Select(s => s);
這種寫法就是所謂的Lambda表示式.實際上Linq語法編譯器在處理時都會轉成Lambda表示式這兩者是一體兩面的東西,只是Linq語法比較貼近SQL對於學習上比較容易,在某些情況下使用Lambda表示式反而容易閱讀.
如果需要做到動態語法產生,在上面的例子處理方式就是先轉為IQueryable介面,然後用組合方式做查詢,如下
IQueryable<string> q = source.AsQueryable();
if(...)
{
q = q.Where(s => s.StartsWith("a"));
}
if(...)
{
q = q.Where(s => s.Length > 2);
}
用這種方式將查詢條件串連起來.
上述作法可以解決大多數的問題,也是很多人採用的方式 .
但在某些如下情況會遇到問題.
1.如果希望IQueryable能夠當作參數傳遞,在某些情況下不適用,譬如說透過WebService或WCF這類情況,原因是IQueryable無法被序列化.
2.某些狀況在上述方式很難實現大多必須透過Linq Expression Tree相關語法,譬如說用動態決定採用or或and,條件的優先運算(譬如(xxx && yyy) || ccc).
以上是Linq Creation主要的用途.
一個簡單的程式範例如下.
string[] source = new string[]{"aaa", "ass", "ccc"};
Criteria<string> criteria = new Criteria<string>();
criteria.Add(new LambdaExpression<string>(s => s.StartsWith("a")));
criteria.Add(new LambdaExpression<string>(s => s.Length == 2));
criteria.AsQueryable(source);
IQueryable本身不可序列化的主因在於IQueryable會綁定來源資料譬如上面的 IQueryable<string> q = source.AsQueryable();
q本身就包含source這是Linq無法序列化的主因之一.
而由上面範例可以看出Criteria類別本身已與source無關,最後在透過AsQueryable函式綁定於Source上,這樣做就有方式讓Criteria允許序列化.所以Criteria本身支援序列化機制,也就可以把Criteria當作參數傳遞,譬如WCF,WCF IRA Service).
而另外還有些範例如下
ICriterion<string> lft = new LambdaExpression<string>(s => s.StartsWith("a"));
ICriterion<string> rgt = new LambdaExpression<string>(s => s.Length == 2);
criteria.Add(new OrExpression<string>(lft, rgt)); //動態使用or連結兩個條件式
criteria.AddOrder(new Order<Customer>("CustomerName", false)); //Order by欄位,欄位名稱使用字串.
其他尚有許多運算子可以參考Nhibernate的 Criteria的相關文章.
當然由於Linq相當複雜(指底層機制),Linq Criteria尚未支援一些Linq特性如join.
下載連結
https://code.msdn.microsoft.com/LinqCreation 如有任何意見歡迎回應.