2010-06-25 36 views
1

我想做一個存儲庫類有一個方法來訂購基於「排序」參數的結果。我需要將它作爲參數傳遞,因爲我試圖對我的存儲庫不返回IQueryable並僅返回List非常嚴格。問題是我不知道如何使它符合以下要求:存儲庫與OrderBy

  1. 允許多列。
  2. 強類型到返回的實體(列沒有字符串作爲參數)。
  3. 能夠按降序設置特定列。

這是甚至可能或無用的,一個存儲庫允許返回與排序?版本庫是否應該能夠執行CRUD操作?也許返回IQueryable將是最好的選擇?

+0

'我想是非常嚴格的,我的倉庫不返回IQueryable的,只有返回List.' - 不要這樣做。 IQueryable/IEnumerable是你的朋友。 (請查看http://google.com/search?q=deferred+execution) – Omar 2010-06-25 16:35:56

回答

6

也許你需要的東西是這樣的:

public class Ordering<T> 
{ 
    private readonly Func<IQueryable<T>, IOrderedQueryable<T>> transform; 

    private Ordering(Func<IQueryable<T>, IOrderedQueryable<T>> transform) 
    { 
     this.transform = transform; 
    } 

    public static Ordering<T> Create<TKey> 
     (Expression<Func<T, TKey>> primary) 
    { 
     return new Ordering<T>(query => query.OrderBy(primary)); 
    } 

    public Ordering<T> ThenBy<TKey>(Expression<Func<T, TKey>> secondary) 
    { 
     return new Ordering<T>(query => transform(query).ThenBy(secondary)); 
    } 

    // And more for the descending methods... 

    internal IOrderedQueryable<T> Apply(IQueryable<T> query) 
    { 
     return transform(query); 
    } 
} 

然後客戶可以創建一個Ordering<T>傳遞到存儲庫,並repositry可以調用ApplyIQueryable<T>。那有意義嗎?

樣品(略帶傻氣)使用方法:

var ordering = Ordering<FileInfo>.Create(fi => fi.Length) 
           .ThenBy(fi => fi.Name); 
+0

是的,這正是我正在尋找的。如何使用此不必從 'repository.GetOrderedBy(訂購 .Create <的EntityType,int>的(E => e.Column))' 使用類型推斷供應類型: 'repository.GetOrderedBy (Ordering.Create(e => e.Column))' 或者這是不可能的,因爲'Ordering.Create'是靜態的? – TheCloudlessSky 2010-06-25 16:27:42

+0

@TheCloudlessSky:哎呀,這是一個錯字。 Create方法應該只聲明一個類型參數。 – 2010-06-25 16:37:22

+0

感謝喬恩,現在有道理。你認爲這樣做是否過分矯枉過正?你認爲最好是返回'IQueryable'並在存儲庫之外進行排序嗎? – TheCloudlessSky 2010-06-25 16:42:37

3

這是有爭議的,但我認爲你的倉庫應該只是返回數據。讓你的消費類擔心集合的排序。

這背後的思考過程非常簡單,消費類無論如何決定訂單。所以他們可以通過它在你的倉庫中手工製作orderby生成器,並讓它完成工作,或者他們可以使用linq並且命令他們從倉庫獲得的集合。我認爲後者更容易實現,不太容易出錯,並且在閱讀代碼時會更有意義,但我認爲我的觀點再次是有爭議的。

+0

如果沒有爭議,我大部分時間都同意你的觀點,但有幾次可以讓儲存庫處理訂購。例如,當實際的數據存儲可以比代碼更高效地排序時,或者如果您需要卸載處理以保持當前系統響應。 – 2010-06-25 16:10:19

+0

我同意你的意見。但是不應該在存儲庫中執行所有的SQL(也就是.ToList())執行,而不是繼續前進? – TheCloudlessSky 2010-06-25 16:10:40

+0

@TheCloudlessSky:爲什麼?這就是IQueryable的要點 - 您允許將數據執行推遲到真正需要時,這意味着您可以防止不必要的複雜查詢對數據庫執行。讓你的倉庫做ToList()只是意味着你將更多的負擔放在你的DB上...... – 2010-06-25 16:18:03

2

我認爲直接返回IQueryable<T>通常是最好的選擇。

例如,假設您有一個方法查詢數據庫以返回特定的表或視圖。如果您的存儲庫的客戶端只需要前10條記錄,並使用自定義條件以及您沒有預料到的排序,則可以通過返回IQueryable<T>來允許這樣做。客戶端只需要添加.Where(...).OrderBy(...).Take(10);

隨着IQueryable<T>,數據層上的調用將自動適應,並且只拉動10條記錄。如果您返回一個List,則您的數據庫查詢將提取每條記錄,然後過濾將需要在您的應用程序中發生。

這增加了巨大的處理/網絡/等開銷,沒有真正的原因。

+0

這是我的這個困境。從我讀過的,最好*不*返回'IQueryable '的存儲庫。 – TheCloudlessSky 2010-06-25 16:12:46

+0

@ TheCloudlessSky:我不知道你在哪裏閱讀過,但我認爲這是一個不好的建議......除非有某些具體的理由來阻止這一點。 – 2010-06-25 16:18:23

+0

首先想到的是,您正在使用這種技術將實際的數據訪問從存儲庫移動到任意位置。它確實解決了列出的問題。 – 2010-06-25 16:20:07