Linq Criteria(1)

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 如有任何意見歡迎回應.