2010-04-28 70 views
41

我想這樣做:如何使用動態字符串參數執行OrderBy?

var orderBy = "Nome, Cognome desc"; 

var timb = time.Timbratures.Include("Anagrafica_Dipendente") 
    .Where(p => p.CodDipendente == 1); 

if(orderBy != "") 
    timb = timb.OrderBy(orderBy); 

是否有OrderBy超載可用,它接受一個字符串參數?

+1

可能重複[如何動態指定Linq OrderBy參數?](http://stackoverflow.com/questions/7265186/how-do-i-specify-the-linq-orderby-argument-dynamically) – Korayem 2016-01-28 14:43:32

+0

這裏是很好的答案。沒有任何第三個庫。 https://stackoverflow.com/a/233505/714828 – 2017-07-04 14:12:27

回答

37

絕對。您可以使用LINQ動態查詢庫,找到on Scott Guthrie's blog。還有一個更新版本on CodePlex

它可以讓你創建OrderBy子句,Where子句,以及幾乎所有其他的通過傳遞字符串參數。它的偉大工程爲排序/過濾網格創建通用代碼等

var result = data 
    .Where(/* ... */) 
    .Select(/* ... */) 
    .OrderBy("Foo asc"); 

var query = DbContext.Data 
    .Where(/* ... */) 
    .Select(/* ... */) 
    .OrderBy("Foo ascending"); 
+2

是否有任何安全問題呢?和LINQ注入一樣,允許用戶輸入到'OrderBy'字段是不安全的嗎?例如'.OrderBy(「UserInput ascending」)。 – jthomperoo 2017-06-09 14:55:30

+0

這是一個Nuget包,爲有興趣的人提供 – ElliotSchmelliot 2018-02-27 19:39:06

5

您需要使用LINQ Dynamic查詢庫,以便在運行時傳遞參數,

這將使LINQ之類的語句

string orderedBy = "Description"; 
var query = (from p in products 
      orderby(orderedBy) 
      select p); 
7

看看這個博客here。它描述了一種通過定義EntitySorter<T>來實現這一點的方法。

它可以讓你在IEntitySorter<T>傳遞到你的服務的方法和使用這樣的:

public static Person[] GetAllPersons(IEntitySorter<Person> sorter) 
{ 
    using (var db = ContextFactory.CreateContext()) 
    { 
     IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons); 

     return sortedList.ToArray(); 
    } 
} 

而且你可以創建一個EntitiySorter這樣的:

IEntitySorter<Person> sorter = EntitySorter<Person> 
    .OrderBy(p => p.Name) 
    .ThenByDescending(p => p.Id); 

或者這樣:

var sorter = EntitySorter<Person> 
    .OrderByDescending("Address.City") 
    .ThenBy("Id"); 
+0

好的答案 - 在自己的類中封裝排序是一個可重複使用和靈活的解決方案 – AlexFoxGill 2016-02-26 09:41:42

55

如果您使用的是簡單的LINQ-to-objects而不想要依賴外部庫,實現你想要的並不難。

OrderBy()子句接受從源元素獲取排序鍵的Func<TSource, TKey>。您可以定義OrderBy()條款外的函數:

Func<Item, Object> orderByFunc = null; 

然後,您可以將其分配給取決於排序標準不同的值:

if (sortOrder == SortOrder.SortByName) 
    orderByFunc = item => item.Name; 
else if (sortOrder == SortOrder.SortByRank) 
    orderByFunc = item => item.Rank; 

然後你可以排序:

var sortedItems = items.OrderBy(orderByFunc); 

此示例假定源類型爲Item,其屬性爲NameRank

請注意,在此示例中,TKeyObject,以不約束可以排序的屬性類型。如果func返回一個值類型(如Int32),它將在排序時被裝箱,並且效率有點低。如果您可以將TKey限制爲特定的值類型,則可以解決此問題。

+3

乾淨,很好的答案,TKey是什麼讓我感到困惑,我認爲它被定義在高端環節,並且不能如此輕易地加蓋。我一直在使用DynLinq分辨率。謝謝你。 – 2012-12-08 22:12:27

+0

如果我需要第一個動態指令降序,第二個升序 - 有沒有一個技巧呢? – 2014-07-23 15:43:23

+2

@YuvalA .:如果其中一個屬性是數字(這包括'DateTime.Ticks'),則可以否定要按相反順序排序的值。否則,您可以有條件地使用OrderBy或OrderByDescending:var sortedItems = reverse? items.OrderByDescending(orderByFunc):items.OrderBy(orderByFunc)'。 – 2014-07-25 11:07:25

22

從codeConcussion另一種解決方案(https://stackoverflow.com/a/7265394/2793768

var param = "Address";  
var pi = typeof(Student).GetProperty(param);  
var orderByAddress = items.OrderBy(x => pi.GetValue(x, null)); 
+3

這不適用於Linq to Entity Framework,因爲它會引發此錯誤「LINQ to Entities does not recognized the method'System.Object GetValue(System.Object,System.Object [])'method,並且此方法無法轉換爲存儲表達式。「 – Korayem 2016-01-28 14:41:41

+0

與此錯誤,你可以嘗試:var orderByAddress = items.AsEnumerable()。OrderBy(x => propertyInfo.GetValue(x,null)) – 2016-02-16 06:39:17

+2

如果他想分頁結果,這不是一件好事。這樣的分頁會在SkipBy與Skip()和Take()之後出現... – 2016-10-31 19:59:08

5

最簡單&的最佳解決方案:

mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s)); 
+0

你確定這沒有語法錯誤? – 2016-07-10 11:17:59

+0

使用System.Linq添加; – 2016-07-10 14:30:38

+0

這可能不適用於'IQueryable'。 – 2017-02-16 09:07:35

-1

在一個答案以上:

最簡單&的最佳解決方案:

mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s)); 

有一個語法錯誤,,null必須添加:

mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s,null)); 
+1

這應該是@Kasper Roma的評論。 – Eiko 2016-10-03 09:36:13

5

你並不需要爲這個外部庫。以下代碼適用於LINQ to SQL /實體。

/// <summary> 
    /// Sorts the elements of a sequence according to a key and the sort order. 
    /// </summary> 
    /// <typeparam name="TSource">The type of the elements of <paramref name="query" />.</typeparam> 
    /// <param name="query">A sequence of values to order.</param> 
    /// <param name="key">Name of the property of <see cref="TSource"/> by which to sort the elements.</param> 
    /// <param name="ascending">True for ascending order, false for descending order.</param> 
    /// <returns>An <see cref="T:System.Linq.IOrderedQueryable`1" /> whose elements are sorted according to a key and sort order.</returns> 
    public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string key, bool ascending = true) 
    { 
     if (string.IsNullOrWhiteSpace(key)) 
     { 
      return query; 
     } 

     var lambda = (dynamic)CreateExpression(typeof(TSource), key); 

     return ascending 
      ? Queryable.OrderBy(query, lambda) 
      : Queryable.OrderByDescending(query, lambda); 
    } 

    private static LambdaExpression CreateExpression(Type type, string propertyName) 
    { 
     var param = Expression.Parameter(type, "x"); 

     Expression body = param; 
     foreach (var member in propertyName.Split('.')) 
     { 
      body = Expression.PropertyOrField(body, member); 
     } 

     return Expression.Lambda(body, param); 
    } 

CreateExpressionhttps://stackoverflow.com/a/16208620/111438複製)

0

我這樣做:

using System.Linq.Expressions; 

namespace System.Linq 
{ 
    public static class LinqExtensions 
    { 

     public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string field, string dir = "asc") 
     { 
      // parametro => expressão 
      var parametro = Expression.Parameter(typeof(TSource), "r"); 
      var expressao = Expression.Property(parametro, field); 
      var lambda = Expression.Lambda<Func<TSource, string>>(expressao, parametro); // r => r.AlgumaCoisa 
      if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase)){ 
       return source.OrderByDescending(lambda); 
      } 
      return source.OrderBy(lambda); 
     } 

     public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, string field, string dir = "asc") 
     { 
      var parametro = Expression.Parameter(typeof(TSource), "r"); 
      var expressao = Expression.Property(parametro, field); 
      var lambda = Expression.Lambda<Func<TSource, string>>(expressao, parametro); // r => r.AlgumaCoisa 
      if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase)) 
      { 
       return source.ThenByDescending(lambda); 
      } 
      return source.ThenBy(lambda); 
     } 

    } 
} 

用途:

example.OrderBy("Nome", "desc").ThenBy("other") 

工作,如:

example.OrderByDescending(r => r.Nome).ThenBy(r => r.other)