2010年8月9日

Linq之動態查詢

Linq之動態查詢。

最近寫Linq碰到一個問題,
就是如果要寫一個查詢系統,這個系統裡面有很多TextBox可以填,
然後撈出符合各個欄位的資料。

在SQL查詢的時候還滿方便的,用字串連連連就可以了,
( 也就是sqlStr += "or name like '%sanc%' " )

那在Linq的話呢,就完全沒有辦法可以用連連連的方法QQ
後來和G神禱告後,G神告訴我目前有三種方法可以處理。

第一是出自MS的Linq Dynamic Query Library
但聽說一堆問題,就懶得去試了。
第二是自己寫運算式樹,也就是建立QueryBuilder
好吧,我有空會再找時間研究看看QQ
第三則是由有名的C# In a Nutshell作者寫的一個Library
( 其實滿想讀他寫的書的,但是全英文....光看這篇,就懶了= = )

總之,最後用了第三個方案,因為真的很方便,也很直覺。
要擴充或是移除,都很方便。

他給的第一個範例是這樣,這個範例沒用到什麼技巧,
反正直接就可以用了。
IQueryable SearchProducts (params string[] keywords)
{
  IQueryable query = dataContext.Products;

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    query = query.Where (p => p.Description.Contains (temp));
  }
return query;
}
這個的功能很簡單,假設你送進去,"可樂"、"暢快",
他就會把在Products的Description(描述)裡面有"可樂"和"暢快"這兩個關鍵字
的內容撈出來,也就是用and的方法。

但是,我們常常需要用到or方法,例如要查詢"可樂"、"雪碧"。
那在用這種查詢方法,就沒辦法查的到了....
( 不可能會出現一種可樂是雪碧口味的吧= =)

ok~所以作者提出了另外一種方法,也就是使用了PredicateBuilder
IQueryable SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
return dataContext.Products.Where (predicate);
}
用Or方法,就可以用or來查詢"可樂"和"雪碧"。
讚吧!!果然是神人級的。

但是看到這邊,不要馬上貼上去使用阿~@@~
因為最重要最重要的關鍵是
我們還沒有PredicateBuilder這個類別阿。

這裡有兩個方法可以使用這個類別。
一、去作者網站下載LinqKit
二、去作者網站將PredicateBuilder的程式碼複製貼上
( 兩個都夠簡單吧= = )

最後,要補充一下,
如果是使用Linq to Entity的話,要把程式碼的最後一行改為
return objectContext.Products.AsExpandable().Where (predicate);
也就是如下程式碼。
IQueryable SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
return objectContext.Products.AsExpandable().Where (predicate);
}
另外,如果要查名子、描述、發行公司等等
很多TextBox的話,怎麼辦呢?
就改成這樣。
var predicate = PredicateBuilder.False();
predicate = predicate.Or(p => p.name.Contains(要查詢的));
predicate = predicate.Or(p => p.Description.Contains (要查詢的));
objectContext.Products.AsExpandable().Where (predicate);
這樣擴充有沒有很容易呢!?

最後,這些我都還沒實驗過,實驗完後,我會再修改這篇文章,
將正確的訊息貼上。

沒有留言:

張貼留言