Come applicare OrderBy su un IQueryable utilizzando un nome di colonna di stringhe all'interno di un metodo di estensione generico?

.net c# entity-framework expression-trees linq

Domanda

public static IQueryable<TResult> ApplySortFilter<T, TResult>(this IQueryable<T> query, string columnName)
  where T : EntityObject
{
  var param = Expression.Parameter(typeof(T), "o");
  var body = Expression.PropertyOrField(param,columnName);

  var sortExpression = Expression.Lambda(body, param);
  return query.OrderBy(sortExpression);
}

Poiché il tipo per OrderBy non viene dedotto da sortExpression, è necessario specificarlo in questo modo in fase di esecuzione:

var sortExpression = Expression.Lambda<T, TSortColumn>(body, param);

O

return query.OrderBy<T, TSortColumn>(sortExpression);

Non penso che sia possibile, tuttavia, poiché TSortColumn può essere determinato solo durante il runtime.

C'è un modo per aggirare questo?

Risposta accettata

Abbiamo fatto qualcosa di simile (non uguale al 100%, ma simile) in un progetto LINQ to SQL. Ecco il codice:

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values) {
    var type = typeof(T);
    var property = type.GetProperty(ordering);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);
    MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
    return source.Provider.CreateQuery<T>(resultExp);
}

In realtà non usavamo un generico, avevamo una classe nota, ma dovrebbe funzionare su un generico (ho messo il segnaposto generico dove dovrebbe essere).

Modifica: per ordine decrescente, passa in OrderByDescending invece di "OrderBy":

MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));

Risposta popolare

Puoi anche utilizzare Dynamic Linq

Informazioni qui http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Scarica C # qui http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Quindi basta aggiungere l'uso di Linq.Dynamic; e ottieni automaticamente 2 ulteriori metodi di estensione che possono essere usati in questo modo

return query.OrderBy("StringColumnName");


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché