2010-04-28 36 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) 
相关问题