網頁

2013年10月11日 星期五

ASP.NET MVC 使用 jQuery EasyUI DataGrid - 多欄排序 (Multiple Column Sorting) Part.2

前一篇「ASP.NET MVC 使用 jQuery EasyUI DataGrid - 多欄排序 (Multiple Column Sorting) Part.1」已經完成了多欄排序的伺服器端的程式內容,不過還是有修改的空間,所以這篇文章就接續完成需要修改的部份。

 


在前一篇裡有提到,在處理多欄排序時我們不使用 Dynamic Expression API 去作多欄位排序的處理,而是改用 IOrderedQueryableHelper 動態產生 IOrderedEnumerable<T>,但如果在啟用多欄排序的情況下只有做單一欄位的排序時,例如進入 Customer/Index 頁面時,DataGrid 的排序是預設對 CustomerID 進行 asc 排序,這樣的情況似乎就不需要使用 IOrderedQueryableHelper 來取得 IOrderedEnumerable<T>,所以因應這樣的情況就將單一欄位排序與多欄排序的處理做個區分。

 

Step.1

將原本在 CustomerService.GetJsonForGrid 方法內的程式給抽出來,

image

建立一個私有方法 GetMultipleColumnSortingQuery  放置剛才所抽離出來的程式,

image

 

Step.2

在之前「ASP.NET MVC 使用 jQuery EasyUI DataGrid - 排序 (Sorting)」這篇文章裡有說過,為預防傳入的 order 與 sort 值有錯誤而造成程式執行的錯誤,所以在 CustomerService 裡針對傳入的 propertyName 會檢查是否為 Customer 的屬性名稱之一。

這個部份我希望不要在程式裡直接給欄位名稱的字串,而是自動從 Entity KeyMemers 裡取得第一個 KeyMember 名稱,讓程式增加彈性,在「Entity Framework 5 - 取得 Entity 的 Property Names 與 KeyMembers」這篇文章裡就有說明過,所以在 EntityHelper.cs 增加以下的程式內容:

image

/// <summary>
/// Keys the members.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static List<string> KeyMembers<T>() where T : class
{
    List<string> result = new List<string>();
 
    string entityName = typeof(T).Name;
 
    string keyMembers = EntityHelper.GetAllEntityKeyMembers()
        .FirstOrDefault(x => x.Key == entityName).Value;
 
    if (!string.IsNullOrWhiteSpace(keyMembers))
    {
        result = keyMembers.Split(',').ToList();
    }
    return result;
}
 
/// <summary>
/// Gets all entity key members.
/// </summary>
/// <returns></returns>
private static Dictionary<string, string> GetAllEntityKeyMembers()
{
    var result = new Dictionary<string, string>();
 
    var mw = new MetadataWorkspace(
        new[] {"res://*/"},
        new[] {Assembly.GetExecutingAssembly()});
 
    var tables = mw.GetItems(DataSpace.CSpace);
 
    foreach (var e in tables.OfType<EntityType>())
    {
        result.Add(e.Name, string.Join(",", e.KeyMembers));
    }
    return result;
}

 

Step.3

接著建立一個 GetSingleColumnSortingQuery 方法,用來操作單一欄位排序的 IQueryalbe<Customer> 的處理,在 GetSingleColumnSortingQuery 方法裡就會使用到 Step.2 所新增加的方法。

image

在資料排序處理的部份就不使用 Dynamic Expression API,而是使用 IOrderedQueryableHelper 來處理。

private IQueryable<Customer> GetSingleColumnSortingQuery(
    int page,
    int pageSize,
    string propertyName,
    string sortOrder)
{
    //取得 Entity 所有的 Property 名稱
    var entityPropertyNames = EntityHelper.EntityPropertyNames<Customer>();
 
    if (!entityPropertyNames.Contains(propertyName))
    {
        propertyName = EntityHelper.KeyMembers<Customer>().FirstOrDefault();
    }
 
    if (!(sortOrder.Equals("asc", StringComparison.OrdinalIgnoreCase)
          || sortOrder.Equals("desc", StringComparison.OrdinalIgnoreCase)))
    {
        sortOrder = "asc";
    }
 
    var query = db.Customers.AsQueryable();
 
    query = sortOrder.Equals("asc", StringComparison.OrdinalIgnoreCase)
        ? query.OrderBy<Customer>(propertyName)
        : query.OrderByDescending<Customer>(propertyName);
 
    query = query.Skip((page - 1) * pageSize).Take(pageSize);
 
    return query;
}

 

Step.4

完成了 GetSingleColumnSortingQuery, GetMultipleColumnSortingQuery 以及增加 EntityHelper 內的程式之後,現在重新修改 CustomerService.GetJsonForGrid 裡的程式。

程式裡並不是直接拿傳進方法的 propertyName 來判斷是否為單一欄位排序或是多欄位排序,而是以處理過 propertyName 與 order 的結果來判斷,以 propertySortTuples 的資料數量來做決定,

image

public JArray GetJsonForGrid(
    int page = 1,
    int pageSize = 10,
    string propertyName = "CustomerID",
    string order = "asc")
{
    // 取得多個排序欄位與順序的 Tuple 結果
    var propertySortTuples =
        EntityHelper.GetPropertySortTuples<Customer>(propertyName, order);
 
    var query = propertySortTuples.Count().Equals(1)
        ? this.GetSingleColumnSortingQuery(page, pageSize, propertyName, order)
        : this.GetMultipleColumnSortingQuery(page, pageSize, propertySortTuples);
    
    JArray ja = new JArray();
 
    foreach (var item in query)
    {
        var itemObject = new JObject
        {
            {"CustomerID", item.CustomerID},
            {"CompanyName", item.CompanyName},
            {"ContactName", item.ContactName},
            {"ContactTitle", item.ContactTitle},
            {"Address", item.Address},
            {"City", item.City},
            {"Region", item.Region},
            {"PostalCode", item.PostalCode},
            {"Country", item.Country},
            {"Phone", item.Phone},
            {"Fax", item.Fax}
        };
        ja.Add(itemObject);
    }
    return ja;
}

 

Step.5

到上一個步驟就完成了我們這一次的修改,那麼這一個步驟還需要做什麼處理呢?

在這一個步驟裡我們可以依照「ASP.NET MVC + NLog + Clutch.Diagnostics.EntityFramework 追蹤 EF 執行的 SQL Command」這一篇文章裡的內容加入 NLog 與 Clutch.Diagnostics.EntityFramework,在進入偵錯模式的時候將 Entity Framework 所產生並執行的 SQL Command 內容顯示在 Visual Studio 的「輸出」視窗內,讓我們即時觀察在單一欄位或多欄位排序處理時在資料庫所執行的 SQL Command 內。

一開始進入 Customer 頁面時,DataGrid 第一次顯示資料的預設查詢

image

多增加了 CompanyName 的排序欄位

image

將 ConmpanyName 的排序順序變更為降冪

image

再增加排序欄位

image

 


最後這邊提醒一下,多欄位的排序先後順序是會依據你點選 DataGrid 欄位表頭時的順序,並不是依據 DataGrid 上所顯示的欄位排列順序,以免有人會錯意而造成誤會,如果要避免讓使用者誤會的話,可以去顯示使用者點選多欄位排序時的選擇先後順序,至於這個方法就留給各位自行去實做出來啦!

 

延伸閱讀:

Entity Framework 5 - 取得 Entity 的 Property Names 與 KeyMembers

ASP.NET MVC + NLog + Clutch.Diagnostics.EntityFramework 追蹤 EF 執行的 SQL Command

 

以上

沒有留言:

張貼留言