如何使用动态字符串参数执行OrderBy?
我想这样做:如何使用动态字符串参数执行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
超载可用,它接受一个字符串参数?
绝对。您可以使用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");
是否有任何安全问题呢?和LINQ注入一样,允许用户输入到'OrderBy'字段是不安全的吗?例如'.OrderBy(“UserInput ascending”)。 – jthomperoo 2017-06-09 14:55:30
这是一个Nuget包,为有兴趣的人提供 – ElliotSchmelliot 2018-02-27 19:39:06
您需要使用LINQ Dynamic查询库,以便在运行时传递参数,
这将使LINQ之类的语句
string orderedBy = "Description";
var query = (from p in products
orderby(orderedBy)
select p);
看看这个博客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");
好的答案 - 在自己的类中封装排序是一个可重复使用和灵活的解决方案 – AlexFoxGill 2016-02-26 09:41:42
如果您使用的是简单的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
,其属性为Name
和Rank
。
请注意,在此示例中,TKey
是Object
,以不约束可以排序的属性类型。如果func返回一个值类型(如Int32
),它将在排序时被装箱,并且效率有点低。如果您可以将TKey
限制为特定的值类型,则可以解决此问题。
干净,很好的答案,TKey是什么让我感到困惑,我认为它被定义在高端环节,并且不能如此轻易地加盖。我一直在使用DynLinq分辨率。谢谢你。 – 2012-12-08 22:12:27
如果我需要第一个动态指令降序,第二个升序 - 有没有一个技巧呢? – 2014-07-23 15:43:23
@YuvalA .:如果其中一个属性是数字(这包括'DateTime.Ticks'),则可以否定要按相反顺序排序的值。否则,您可以有条件地使用OrderBy或OrderByDescending:var sortedItems = reverse? items.OrderByDescending(orderByFunc):items.OrderBy(orderByFunc)'。 – 2014-07-25 11:07:25
从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));
这不适用于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
与此错误,你可以尝试:var orderByAddress = items.AsEnumerable()。OrderBy(x => propertyInfo.GetValue(x,null)) – 2016-02-16 06:39:17
如果他想分页结果,这不是一件好事。这样的分页会在SkipBy与Skip()和Take()之后出现... – 2016-10-31 19:59:08
最简单&的最佳解决方案:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
你确定这没有语法错误? – 2016-07-10 11:17:59
使用System.Linq添加; – 2016-07-10 14:30:38
这可能不适用于'IQueryable'。 – 2017-02-16 09:07:35
在一个答案以上:
最简单&的最佳解决方案:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
有一个语法错误,,null
必须添加:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s,null));
这应该是@Kasper Roma的评论。 – Eiko 2016-10-03 09:36:13
你并不需要为这个外部库。以下代码适用于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);
}
(CreateExpression
从https://stackoverflow.com/a/16208620/111438复制)
我这样做:
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)
可能重复[如何动态指定Linq OrderBy参数?](http://stackoverflow.com/questions/7265186/how-do-i-specify-the-linq-orderby-argument-dynamically) – Korayem 2016-01-28 14:43:32
这里是很好的答案。没有任何第三个库。 https://stackoverflow.com/a/233505/714828 – 2017-07-04 14:12:27