我需要在Linq(to Entity)語句中支持可變數量的Orderby條款。也就是說,我的函數將接受數據應該按順序排列的屬性列表。屬性可以有升序或降序排序。處理構建Linq查詢的最佳方式是什麼?Linq處理可變數量的OrderBy
謝謝!
我需要在Linq(to Entity)語句中支持可變數量的Orderby條款。也就是說,我的函數將接受數據應該按順序排列的屬性列表。屬性可以有升序或降序排序。處理構建Linq查詢的最佳方式是什麼?Linq處理可變數量的OrderBy
謝謝!
要按任意屬性排序,您需要構建一個表達式樹來傳遞給OrderBy
。
要按任意數量的屬性排序,您需要在循環中調用ThenBy
。
你應該能夠沿着這些線路做一些事情:
public IEnumerable<MyType> DoSomething(params Expression<Func<MyType,object>>[] properties)
{
var query = // create LINQ query that returns IQueryable<MyType>
query = query.OrderBy(properties.First());
foreach (var property in properties.Skip(1))
{
query = query.ThenBy(property);
}
}
…
var results = DoSomething(() => x.Age,() => x.Height,() => x.LastName);
你需要處理它指定少於2種性能的情況下。
從Jay's answer繼,這可以做成一個不錯的擴展方法:
public static class EnumerableExtensions
{
public static IEnumerable<T> OrderByMany<T>(this IEnumerable<T> enumerable,
params Expression<Func<T, object>>[] expressions)
{
if (expressions.Length == 1)
return enumerable.OrderBy(expressions[0].Compile());
var query = enumerable.OrderBy(expressions[0].Compile());
for (int i = 1; i < expressions.Length;i++)
{
query = query.ThenBy(expressions[i].Compile());
}
return query;
}
}
使用變得非常簡單,給出一個測試對象:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
然後,這是可能的:
var people = new Person[]
{
new Person() {Name = "John", Age = 40},
new Person() {Name = "John", Age = 20},
new Person() {Name = "Agnes", Age = 11}
};
foreach(var per in people.OrderByMany(x => x.Name, x => x.Age))
{
Console.WriteLine("{0} Age={1}",per.Name,per.Age);
}
輸出:
Agnes Age=11
John Age=20
John Age=40
UPDATE
您可以添加OrderByMany
方法來支持SortOrder的還有另一個過載,雖然它相當迅速變得笨重。個人而言,我只希望去的語法
var query = from p
in people
order by Name, Age descending;
然而,備案,在C#4至少,我會完成使用枚舉&元組過載。
public enum SortOrder
{
Ascending,
Descending
}
和額外的過載:
public static IEnumerable<T> OrderByMany<T>(this IEnumerable<T> enumerable,
params Tuple<Expression<Func<T, object>>,SortOrder>[] expressions)
{
var query = (expressions[0].Item2 == SortOrder.Ascending)
? enumerable.OrderBy(expressions[0].Item1.Compile())
: enumerable.OrderByDescending(expressions[0].Item1.Compile());
for (int i = 1; i < expressions.Length; i++)
{
query = expressions[i].Item2 == SortOrder.Ascending
? query.ThenBy(expressions[i].Item1.Compile())
: query.ThenByDescending(expressions[i].Item1.Compile());
}
return query;
}
使用變得笨拙,難以閱讀:
foreach (var per in people.OrderByMany(
new Tuple<Expression<Func<Person, object>>, SortOrder>(x => x.Age, SortOrder.Descending),
new Tuple<Expression<Func<Person, object>>, SortOrder>(x => x.Name, SortOrder.Ascending)))
{
Console.WriteLine("{0} Age={1}", per.Name, per.Age);
}
我喜歡Jamiec的想法,但我討厭使用的元組,因爲語法是醜陋的。因此,我創建了一個封裝Tuple的小類,併爲Item1和Item2屬性提供了更好的變量名稱的getter。
另請注意,我使用了升序的默認排序順序,因此如果要按降序排序,只需指定SortOrder。
public class SortExpression<T>
{
private Tuple<Expression<Func<T, object>>, SortOrder> tuple;
public SortExpression(Expression<Func<T, object>> expression, SortOrder order =SortOrder.Ascending)
{
tuple = new Tuple<Expression<Func<T,object>>, SortOrder>(expression, order);
}
public Expression<Func<T, object>> Expression {
get { return tuple.Item1; }
}
public SortOrder Order {
get { return tuple.Item2; }
}
}
在我的具體應用中,我有一個存儲庫基類,它需要一個IQueryable並將其轉換爲ObservableCollection。在該方法中我使用的SortExpression類:
public ObservableCollection<T> GetCollection(params SortExpression<T>[] sortExpressions) {
var list = new ObservableCollection<T>();
var query = FindAll();
if (!sortExpressions.Any()) {
query.ToList().ForEach(list.Add);
return list;
}
var ordered = (sortExpressions[0].Order == SortOrder.Ascending)
? query.OrderBy(sortExpressions[0].Expression.Compile())
: query.OrderByDescending(sortExpressions[0].Expression.Compile());
for (var i = 1; i < sortExpressions.Length; i++) {
ordered = sortExpressions[i].Order == SortOrder.Ascending
? ordered.ThenBy(sortExpressions[i].Expression.Compile())
: ordered.ThenByDescending(sortExpressions[i].Expression.Compile());
}
ordered.ToList().ForEach(list.Add);
return list;
}
下面是使用方法:
var repository = new ContactRepository(UnitOfWork);
return repository.GetCollection(
new SortExpression<Contact>(x => x.FirstName),
new SortExpression<Contact>(x => x.LastName));
謝謝! 可以修改OrderBYMany來支持傳遞IComparer嗎? – JerryKur 2011-01-24 18:10:31