问题
I want to do this:
var orderBy = "Nome, Cognome desc";
var timb = time.Timbratures.Include("Anagrafica_Dipendente")
.Where(p => p.CodDipendente == 1);
if(orderBy != "")
timb = timb.OrderBy(orderBy);
Is there an OrderBy
overload available that accepts a string parameter?
回答1:
Absolutely. You can use the LINQ Dynamic Query Library, found on Scott Guthrie's blog. There's also an updated version available on CodePlex.
It lets you create OrderBy
clauses, Where
clauses, and just about everything else by passing in string parameters. It works great for creating generic code for sorting/filtering grids, etc.
var result = data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo asc");
var query = DbContext.Data
.Where(/* ... */)
.Select(/* ... */)
.OrderBy("Foo ascending");
回答2:
If you are using plain LINQ-to-objects and don't want to take a dependency on an external library it is not hard to achieve what you want.
The OrderBy()
clause accepts a Func<TSource, TKey>
that gets a sort key from a source element. You can define the function outside the OrderBy()
clause:
Func<Item, Object> orderByFunc = null;
You can then assign it to different values depending on the sort criteria:
if (sortOrder == SortOrder.SortByName)
orderByFunc = item => item.Name;
else if (sortOrder == SortOrder.SortByRank)
orderByFunc = item => item.Rank;
Then you can sort:
var sortedItems = items.OrderBy(orderByFunc);
This example assumes that the source type is Item
that have properties Name
and Rank
.
Note that in this example TKey
is Object
to not constrain the property types that can be sorted on. If the func returns a value type (like Int32
) it will get boxed when sorting and that is somewhat inefficient. If you can constrain TKey
to a specific value type you can work around this problem.
回答3:
Another solution from 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));
回答4:
You don't need an external library for this. The below code works for LINQ to SQL/entities.
/// <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
copied from https://stackoverflow.com/a/16208620/111438)
回答5:
The simplest & the best solution:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
回答6:
Look at this blog here. It describes a way to do this, by defining an EntitySorter<T>
.
It allows you to pass in an IEntitySorter<T>
into your service methods and use it like this:
public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
using (var db = ContextFactory.CreateContext())
{
IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons);
return sortedList.ToArray();
}
}
And you can create an EntitiySorter
like this:
IEntitySorter<Person> sorter = EntitySorter<Person>
.OrderBy(p => p.Name)
.ThenByDescending(p => p.Id);
Or like this:
var sorter = EntitySorter<Person>
.OrderByDescending("Address.City")
.ThenBy("Id");
回答7:
I did so:
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>;
}
}
}
Use :
example.OrderBy("Nome", "desc").ThenBy("other")
Work like:
example.OrderByDescending(r => r.Nome).ThenBy(r => r.other)
回答8:
You need to use the LINQ Dynamic Query Library in order to pass parameters at runtime,
This will allow linq statements like
string orderedBy = "Description";
var query = (from p in products
orderby(orderedBy)
select p);
回答9:
In one answer above:
The simplest & the best solution:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
There is an syntax error, ,null
must be added:
mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s,null));
来源:https://stackoverflow.com/questions/2728340/how-can-i-do-an-orderby-with-a-dynamic-string-parameter