2011-03-20 57 views
1

我的業務層將所有必需的信息傳遞給UI層。從我讀過的內容來看,一般來說,最佳做法是將提取的數據發送到UI層,並避免傳遞ObjectQuery之類的查詢。我的問題是這種方法是:如何有效地處理Where和OrderBy子句

如果我要做出靈活的業務層,那麼我應該允許UI對數據進行排序,無論如何它都需要。從數據庫中獲取排序後的數據,然後在用戶界面中對它們進行處理對我來說是不好的做法,所以唯一的辦法是以某種方式

那麼我的選擇是什麼?有沒有一種方法,使這樣的:

public void OrderByMethod(params ...) { .... } 

這樣我就可以這樣調用:

OrderByMethod(MyEntity.Property1, MyEntity.Property2 descending....); 

感謝, 戈蘭

+0

最簡單的方法是使用* Dynamic Linq * - 如果你搜索這些條款,你會發現很多例子。還可以查看http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx – BrokenGlass 2011-03-20 16:11:51

回答

1

如果您不直接向用戶界面公開IQueryable(可能不是因爲您在UI和數據訪問層之間使用業務層),那麼您可以使用自定義對象傳遞「列表信息」。它可以是這樣的:

public class ListOptions<T> 
{ 
    // Paging 
    public int Page { get; set; } 
    public int PageSize { get; set; } 
    // Sorting 
    public IList<SortOptions<T>> SortOptions { get; set; } 
} 

public class SortOptions<T> 
{ 
    public Expression<Func<T, object>> SortProperty { get; set; } 
    public bool IsDescending { get; set; } 
} 

您將使用它作爲您的業務方法返回的數據和業務方法裏面,你會使用自定義擴展與EF或倉庫提供IQueryable工作的參數:

public static class QueryableExtensions 
{ 
    public static IQueryable<T> ApplyListOptions<T>(this IQueryable<T> query, ListOptions<T> options) 
    { 
     if (options != null && options.SortOptions.Count > 0) 
     { 
      IOrderedQueryable<T> orderedQuery = query.ApplyOrderBy(options.SortOptions[0]); 

      for (int i = 1; i < options.SortOptions.Count; i++) 
      { 
       orderedQuery = orderedQuery.ApplyThenBy(options.SortOptions[i]); 
      } 

      query = orderedQuery.ApplyPaging(options.Page, options.PageSize); 
     } 

     return query; 
    } 

    public static IOrderedQueryable<T> ApplyOrderBy<T>(this IQueryable<T> query, SortOptions<T> sortOption) 
    { 
     if (sortOption.IsDescending) 
     { 
      return query.OrderByDescending(sortOption.SortProperty); 
     } 

     return query.OrderBy(sortOption.SortProperty); 
    } 

    public static IOrderedQueryable<T> ApplyThenBy<T>(this IOrderedQueryable<T> query, SortOptions<T> sortOption) 
    { 
     if (sortOption.IsDescending) 
     { 
      return query.ThenByDescending(sortOption.SortProperty); 
     } 

     return query.ThenBy(sortOption.SortProperty); 
    } 

    public static IQueryable<T> ApplyPaging<T>(this IOrderedQueryable<T> query, int page, int pageSize) 
    { 
     if (pageSize > 0) 
     { 
      return query.Skip((page - 1)*pageSize).Take(pageSize); 
     } 

     return query; 
    } 
} 

所以,你的處理方法可以看起來像:

public IEnumerable<User> GetUsers(ListOptions<User> listOptions) 
{ 
    return _context.Users.ApplyListOptioins(listOptions).AsEnumerable(); 
} 

而且你會調用該方法,如:

var options = new ListOptions<User> 
    { 
     Page = 2, 
     PageSize = 3, 
     SortOptions = new List<SortOptions<User>> 
      { 
       new SortOptions<User> 
        { 
         IsDescending = false, 
         SortProperty = u => u.LastName 
        }, 
       new SortOptions<User> 
        { 
         IsDescending = true, 
         SortProperty = u => u.FirstName 
        } 
      } 
    }; 


var data = usersService.GetUsers(options);   
0

如何被從一個層傳遞到數據另一個?它聽起來像你正在使用簡單的存儲庫模式,是否正確?如果是這樣,存儲庫方法通常返回什麼?

對於數據層和業務層(假設沒有硬分隔,例如Web服務層)以IEnumerable<T>IQueryable<T>的形式傳遞數據通常是很好的做法。這樣當數據到達用戶界面時,UI代碼就可以很容易地繼續根據需要操作數據(排序,分頁等)。

實際上,如果實際數據不是,那麼它將被枚舉爲,直到它到達用戶界面,那麼它甚至不應該在此之前發出數據庫請求。這允許將整個結果集的IEnumerable<T>邏輯地傳遞給UI,然後讓UI確定它僅需要記錄的第一個「頁面」(例如,通過調用.Take()並且僅抓取前10個)。這樣,您可以在整個應用程序的許多不同位置使用一個非常簡單的存儲庫方法,從而減少業務量,並將邏輯顯示到數據層中。