Linq 如何使用动态字符串参数执行OrderBy?
我想这样做:Linq 如何使用动态字符串参数执行OrderBy?,linq,sql-order-by,Linq,Sql Order By,我想这样做: 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动态查询库。还有一个更新版本可
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动态查询库。还有一个更新版本可用
它允许您通过传入字符串参数来创建OrderBy
子句、Where
子句以及几乎所有其他内容。它非常适合创建用于排序/过滤网格等的通用代码
var result = data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo asc");
var query = DbContext.Data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo ascending");
您需要使用LINQ查询库以便在运行时传递参数
这将允许linq语句,如
string orderedBy = "Description";
var query = (from p in products
orderby(orderedBy)
select p);
看看这个博客。它描述了一种方法,通过定义EntitySorter
它允许您将IEntitySorter
传递到您的服务方法中,并按如下方式使用:
public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
using (var db = ContextFactory.CreateContext())
{
IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons);
return sortedList.ToArray();
}
}
IEntitySorter<Person> sorter = EntitySorter<Person>
.OrderBy(p => p.Name)
.ThenByDescending(p => p.Id);
var sorter = EntitySorter<Person>
.OrderByDescending("Address.City")
.ThenBy("Id");
或者像这样:
public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
using (var db = ContextFactory.CreateContext())
{
IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons);
return sortedList.ToArray();
}
}
IEntitySorter<Person> sorter = EntitySorter<Person>
.OrderBy(p => p.Name)
.ThenByDescending(p => p.Id);
var sorter = EntitySorter<Person>
.OrderByDescending("Address.City")
.ThenBy("Id");
var-sorter=EntitySorter
.OrderByDescending(“Address.City”)
。然后(“Id”);
如果您使用的是普通LINQ对象,并且不想依赖外部库,那么实现您想要的并不难
OrderBy()
子句接受从源元素获取排序键的Func
。您可以在OrderBy()
子句之外定义函数:
Func<Item, Object> orderByFunc = null;
然后您可以排序:
var sortedItems = items.OrderBy(orderByFunc);
本例假设源类型为Item
,其属性为Name
和Rank
请注意,在本例中,
TKey
是Object
,不约束可以排序的属性类型。如果func返回值类型(如Int32
),则排序时会将其装箱,这有点低效。如果可以将TKey
约束为特定的值类型,则可以解决此问题。codeConcussion()的另一个解决方案
最简单和最好的解决方案:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
在上面的一个答复中:
最简单和最好的解决方案:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
出现语法错误,,必须添加null
:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s,null));
这不需要外部库。下面的代码适用于LINQ到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);
}
//
///根据键和排序顺序对序列的元素进行排序。
///
///的元素的类型。
///按顺序排列的一系列值。
///要按其对元素进行排序的属性的名称。
///对于升序为True,对于降序为false。
///根据键和排序顺序对其元素进行排序的对象。
公共静态IQueryable OrderBy(此IQueryable查询,字符串键,bool升序=true)
{
if(string.IsNullOrWhiteSpace(key))
{
返回查询;
}
var lambda=(动态)CreateExpression(typeof(TSource),key);
升序返回
?可查询的.OrderBy(查询,lambda)
:Queryable.OrderByDescending(查询,lambda);
}
私有静态LambdaExpression CreateExpression(类型类型,字符串属性名称)
{
var param=表达式参数(类型为“x”);
表达式body=param;
foreach(propertyName.Split('.')中的变量成员)
{
body=Expression.PropertyOrField(body,member);
}
返回表达式.Lambda(body,param);
}
(CreateExpression
复制自)我这样做了:
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(expressao, parametro); // r => r.AlgumaCoisa
var tipo = typeof(TSource).GetProperty(field).PropertyType;
var nome = "OrderBy";
if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
{
nome = "OrderByDescending";
}
var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
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
var tipo = typeof(TSource).GetProperty(field).PropertyType;
var nome = "ThenBy";
if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
{
nome = "ThenByDescending";
}
var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
}
}
}
工作方式如下:
example.OrderByDescending(r => r.Nome).ThenBy(r => r.other)
干净,很好的回答,TKey是让我困惑的东西,我认为它的定义在链的更高层,不能那么容易地盖章。我使用DynLinq分辨率已经有一段时间了。谢谢。如果我需要第一个动态顺序是降序,第二个是升序,有什么诀窍吗?@YuvalA:如果其中一个属性是数字的(这包括
DateTime.Ticks
),你可以将该值取反,以相反的顺序排序。否则,您可以有条件地使用OrderBy
或OrderByDescending
:var sortedItems=reverse?items.OrderByDescending(orderByFunc):items.OrderBy(orderByFunc)
。对于每个属性,我需要添加一个if条件?这在Linq to Entity框架中不起作用,因为它会引发此错误Linq to Entities无法识别方法'System.Object GetValue(System.Object,System.Object[]),此方法无法转换为存储表达式。
如果出现此错误,您是否可以尝试:var orderByAddress=items.AsEnumerable().OrderBy(x=>propertyInfo.GetValue(x,null))如果要对结果进行分页,这不是一件好事。这样的分页将在OrderBy之后使用Skip()和Take()…您不能在Linq中插入意外的条件以实现可序列化。您只能获取数据,以便能够使用所有C#功能处理它,这是不可执行的。这里的可能副本是一个很好的答案。没有第三个图书馆。对于实体框架,请参见answer(使用EF.property
)Great answer-将排序封装在其自己的类中是一种可重用且灵活的解决方案添加使用System.Linq;这太棒了。这应该是@Kasper Roma的评论。这有任何安全问题吗?与LINQ注入一样,允许用户输入到OrderBy
字段是否不安全?e、 g.OrderBy(“UserInput升序”)。
这是一个适用于这些用户的Nuget包interested@jthomperoo,您应该始终在此处验证用户输入。这很简单。@jthomperoo:任何注入SQL的未初始化字符串值都是一个问题,无论您将其注入到何处。我有理由认为DynamicIQ会清理输入,但在我将其投入生产之前,我不会盲目信任它。通过使用Expression.Lambda,您期望该属性是字符串类型。您是对的,当我编写代码时,我仅将其用于字符串。我也编辑了其他类型。如何使该方法适用于其他类型。你们有一个例子吗?我确认这是可行的,但当TSource是私有类时它不起作用