More

    搜索頁面 – Service層的工作 -動態產生Linq條件 (.NET MVC 5 Ch-22)

    在上一篇介紹完了會使用到的ViewModel之後,接下來就是實際的商業邏輯,也就是實際做搜索和產生資料的部份。

    在這一篇,將會介紹如何透過Service層和ViewModel的搭配,讓使用起來變的更加方便。

    同步發表於我的部落格:http://alantsai2007.blogspot.com/2014/10/BuildYourOwnApplicationFrameworkOnMvc-22-IndexPage-DynamicWhereLinq.html

    功能描述

    Service的流程大概如下:

    1. 依照SearchViewModel裡面的欄位去做DB搜索
    2. 得出的結果將會用Automapper轉成要的SearchResultViewModel,並且透過PagedList.Mvc的方式把資料包住
    3. View方面的呈現 – 搜索表單可以做成通用的Partial

    由於Service要做的事情也滿多的,因此整個Service層的實作會分幾篇來介紹。

    Service依照SearchViewModel裡面的欄位去做搜索

    這個部份其實要拆成兩塊:

    1. 動態組裝Linq條件 – Linq搜索的好處是強型別的條件,但是當我們希望Service自動依照欄位去做搜索的時候,Linq就不方便使用了。因此,我們需要先瞭解如何動態組裝Linq條件
    2. 透 過Reflection取得搜索欄位和條件 – SearchViewModelBase裡面有必要有的欄位(例如目前第幾頁,用什麼欄位做排序,詳細請看上一篇),但是這些欄位和實際搜索的DB沒有關 係,SearchViewModelBase 裡面是方便做分頁用的,而實際的搜索條件是每一個繼承下來需要的,因此透過Reflection可以做到。

    動態組裝的Linq

    基本上,動態組裝Linq條件有3種方法:

    1. 使用PredicateBuilder – 強型別的方式組裝linq條件
    2. 使用Dynamic Linq Library – 用string的方式組裝Linq
    3. 自己組裝Expression Tree

    自己寫Expression Tree

    基本上Linq的Where條件最終組出來就是一個Expression Tree。因此如果對於Expression Tree有所瞭解可以自己動手寫。

    但是基本上要會寫這個要對於整個比較瞭解,因此基本不用考慮。

    使用PredicateBuilder

    PredicateBuilder基本上就是可以用強型別的方式組裝Linq條件。舉例來說,我們使用Linq來寫Where條件,當Where條件寫好只好,是沒有辦法在對那個Where條件在做調整。

    因此,假設我們的搜索表單有4個條件,有輸入才做搜索條件,如果條件是兩個以上,還要做and的邏輯。要用原生的linq做到這個其實是很困難的,因為Linq條件是不能在改,因此等於每一種情況都要寫一個,這個很難維護也很麻煩。

    因此,PredicateBuilder就很方便,它能夠讓我們動態修改Linq條件,因此舉例來說(官方的例子):

    IQueryable<Product> SearchProducts (params string[] keywords)
    {
      var predicate = PredicateBuilder.False<Product>();
    
      foreach (string keyword in keywords)
      {
        string temp = keyword;
        predicate = predicate.Or (p => p.Description.Contains (temp));
      }
      return dataContext.Products.Where (predicate);
    }
    

    有一堆搜索的Keyword,每一個要以Or的方式做搜索,不是用PredicateBuilder,原生的Linq是辦不到的(如果全部要做and是做的到,但是or就沒有辦法)。

    LinqKit 套件

    PredicateBuilder屬於LinqKit套件的一部份,這個套件提供了一些方便處理Linq的方法。

    1. Nuget安裝指令:Install-Package LinqKit
    2. Nuget頁面:LinqKit
    3. 官方介紹Predicate Builder:Dynamically Composing Expression Predicates
    4. 官方介紹LinqKit:What is LINQKit?

    PredicateBuilder非常適合在確定有那些欄位的情況下使用。例如確定有4個搜索欄位。但是,這個不適合我們使用。因為如果要寫共通處理邏輯,更本就不知道有那些搜索欄位。

    Dynamic Linq Query

    早期在寫Sql的時候,有時候Sql的語法使用string組裝在一起(當然要用NameParameter避免Sql injection)。這一種組裝的好處是完全可以寫好一個共用邏輯,只要符合條件的就用string concat的方式組裝條件,非常的方便。

    Linq如果可以做到就好了,因此由Scot Gu介紹了一個所謂的Dynamic Linq Query – Dynamic LINQ

    Dynamic Linq Query基本上就是可以讓我們用string方式組裝linq,因此(下面範例是由保哥一篇介紹的文章裡面截取):

    Northwind db = new Northwind(connString); 
    db.Log = Console.Out;
    
    var query =
        db.Customers.Where("City == @0 and Orders.Count >= @1", "London", 10).
        OrderBy("CompanyName").
        Select("New(CompanyName as Name, Phone)");
    
    Console.WriteLine(query);
    Console.ReadLine();
    

    Dynamic Linq Query

    基本上這個功能並沒有包含在.Net裡面,如果要使用之前是需要到Scott Gu的那篇文章下載dll。不過有人把它包到了Nuget,方便使用

    Dynamic Linq Query非常適合做那種通用型的處理,例如不知道欄位有什麼的情況下。但是壞處是,喪失了強型別的好處。不過這個非常適合框架處理搜索條件。

    結語

    本來這一篇還要介紹框架Service層如何搭配Dynamic Linq Query來使用,不過在介紹動態Linq條件的時候,篇幅有點長,因此就把Service層的實作留在下一篇。

    Recent Articles

    spot_img

    Related Stories

    Stay on op - Ge the daily news in your inbox