2012-08-16 97 views
2

我想構建一個通用的查詢機制來訪問我的存儲庫。我希望使用Lambda表達式來篩選和排序查詢。我正在努力尋找一種方法來傳遞通用的Lambda表達式列表,特別是爲了順序排列,並希望能夠爲此提供幫助。編輯:2要求我試圖滿足的是,不暴露超出存儲庫的IQueryable,但仍然能夠在數據庫級別進行一些過濾和排序。OrderBy Lambda的泛型列表

爲了更好地說明這一點讓我告訴你的代碼

public class Query<T> 
{ 
    public class OrderBy<T> 
    { 
     public Expression<Func<T, **int**>> Clause { set; get; } // Order By clause 
     public bool Descending = true; 
    } 

    public Expression<Func<T, bool>> Where { set; get; } // Where clause 
    public IList<OrderBy<T>> OrderBys { set; get; } // Where clause 

    public Query() 
    { 
     OrderBys = new List<OrderBy<T>>(); 
    } 
}  

    public IEnumerable<Person> FindBy(Query<Person> query) 
    { 
     IQueryable<Person> Temp = GetObjectSet(); 
     if (query.Where != null) Temp = Temp.Where(query.Where); 
     foreach (var OrderByThis in query.OrderBys) 
     { 
      if (OrderByThis.Descending) Temp = Temp.OrderByDescending(OrderByThis.Clause); 
      else Temp = Temp.OrderBy(OrderByThis.Clause); 
     } 

     return Temp.ToList<Person>(); 
    } 

這是非常好的,但表達< Func鍵< T,INT >>是不通用的。我需要能夠做到這樣的事情:

Query<Person> query = new Query<Person>(); 
Query<Person>.OrderBy<Person> clause1 = new Query<Person>.OrderBy<Person>(); 
clause1.Clause = m => m.Username; 
Query<Person>.OrderBy<Person> clause2 = new Query<Person>.OrderBy<Person>(); 
clause2.Clause = m => m.DateOfBirth; 
query.OrderBys.Add(clause1); 
query.OrderBys.Add(clause2); 

即即將添加一些不同類型的不同字段。

我想必須有一種方法來將它們存儲爲通用Lambda函數,然後在存儲庫中轉換爲它所需的強類型Lambda函數。

我該怎麼做?

+0

.NET已經提供訂購和排序,以擴展方法,如'.OrderBy'和'機制。在哪裏和一個更乾淨的語法。爲什麼不公開像'repository.Get(Func ,IEnumerable queryExpression)''? (或者如果你需要解析表達式樹,使它成爲'Expression Jay 2012-08-16 01:31:12

+0

我不太喜歡對不起,可以舉一個具體的例子嗎? – 2012-08-16 01:48:14

+0

你可以使用'object'作爲你的類型嗎? – Gabe 2012-08-16 01:49:26

回答

1

正如我在我對your other question的回答中所指出的那樣,我一般會勸阻這種方法。暴露IQueryable<T>/IOrderedQueryable<T>更有意義。

這就是說,在您選擇的How to pass multiple Expressions to OrderBy for EF?答案中可以找到符合您意向的解決方案。

它允許您使用的語法,如:

var query = context.Users ... ; 

var queryWithOrderBy = ApplyOrderBy(query, 
    new OrderByExpression<User, string>(expression: u => u.UserName, descending: false), // a string, asc 
    new OrderByExpression<User, int>(expression: u => u.UserId, descending: true)); // an int, desc 

var result = queryWithOrderBy.ToList(); // didn't throw an exception for me 
+0

謝謝@smartcaveman,我很高興地得出同樣的結論。我仍然希望得到這個通用查詢排序,但我懷疑我最終只會暴露IQueryable。 – 2012-08-16 04:02:09

+1

@DaleBurrell,你會的。在走向我的感官之前,我也走了一段路。 – smartcaveman 2012-08-16 04:08:03

+0

那麼解決方案的工作原理,我確信有一個更好的解決方案。但無論如何回到IQueryable :)謝謝 – 2012-08-16 05:09:08

1

詳細闡述了我的評論,我不明白爲什麼需要從表達式中構建自己的中間查詢對象,然後重構該中間對象中的表達式,當時可以完全跳過該翻譯。

鑑於您的示例查詢:

repository.FindBy(people => people.OrderBy(p => p.Username).ThenBy(p => p.DateOfBirth)); 

留意,你仍然可以建立查詢增量,如果根據用戶的選擇正在做它,例如。下面的查詢等效於上面的:

Func<IEnumerable<Person>, IEnumerable<Person>> query = people => people.OrderBy(p => p.Username); 
query = query.ThenBy(p => p.DateOfBirth); 

我知道你不想暴露IQueryable超越庫,但是你仍然可以使用LINQ與簽名,如:

public IEnumerable<Person> FindBy(Func<IEnumerable<Person>, IEnumerable<Person>> query) 
{ 
    return query(GetObjectSet()).ToList(); 
} 

但是,對於您的實際問題,您可以使用Expression<Func<T, object>>Clause屬性類型實現您的OrderBy任務,或者如果這使您感到不安,則可以使用IComparable而不是對象,因爲它實際上就是你需要的所有命令,並且字符串和數字類型都可以實現它。

+0

來解決排序問題我剛試過你的解決方案,並且意識到我已經忘記提到2個要求,即不要將IQueryable暴露在存儲庫之外,但仍然能夠執行一些數據庫級別的過濾和排序。您的解決方案不使用實體框架,它假定是因爲它使用IEnumerable嗎? – 2012-08-16 02:26:39

+0

@DaleBurrell好的,我在問題中添加了EF標籤。您是否嘗試過第二種選擇('FindBy(Func Jay 2012-08-16 02:31:22

+0

感謝Jay,是的,我正在使用第二個選項,並且在查詢分析器中它沒有傳遞任何過濾/排序信息。使用IComarable很好地編譯!但代碼本身不起作用 - 這可能是另一個問題的主題,除非你有任何想法? – 2012-08-16 02:48:49