¿Cómo aplico OrderBy en un IQueryable usando un nombre de columna de cadena dentro de un método de extensión genérico?

.net c# entity-framework expression-trees linq

Pregunta

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);
}

Debido a que el tipo de OrderBy no se deduce de sortExpression, necesito especificarlo de esta manera en el tiempo de ejecución:

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

O

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

No creo que esto sea posible, sin embargo, como TSortColumn solo se puede determinar durante el tiempo de ejecución.

¿Hay alguna forma de evitar esto?

Respuesta aceptada

Hicimos algo similar (no el 100% igual, pero similar) en un proyecto LINQ to SQL. Aquí está el código:

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);
}

En realidad no usamos un genérico, teníamos una clase conocida, pero debería funcionar en un genérico (he puesto el marcador de posición genérico donde debería estar).

Edición: Para un orden descendente, pase en OrderByDescending en lugar de "OrderBy":

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

Respuesta popular

También puedes usar Dynamic Linq.

Información aquí http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

C # descargue aquí http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Luego simplemente agregue el uso de Linq.Dynamic; y automáticamente obtienes 2 métodos de extensión adicionales que se pueden usar de esta manera

return query.OrderBy("StringColumnName");


Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow