Me gustó la respuesta de @Mark Powell, pero como @ShuberFu dijo, da el error LINQ to Entities only supports casting EDM primitive or enumeration types
.
La eliminación de var propAsObject = Expression.Convert(property, typeof(object));
no funcionaba con las propiedades que eran tipos de valores, como enteros, ya que no implícitamente insertaría el int en el objeto.
Usando Ideas de Kristofer Andersson y Marc Gravell Encontré una manera de construir la función Queryable usando el nombre de la propiedad y hacer que funcione con Entity Framework. También incluí un parámetro opcional de IComparer. Precaución: El parámetro IComparer no funciona con Entity Framework y se debe omitir si se usa Linq a Sql.
Los siguientes trabajos con Entity Framework y LINQ to SQL:
query = query.OrderBy("ProductId");
Y @Simon Scheurer Esto también funciona:
query = query.OrderBy("ProductCategory.CategoryId");
Y si no está utilizando Entity Framework o LINQ to SQL, esto funciona :
query = query.OrderBy("ProductCategory", comparer);
Aquí está el código:
public static class IQueryableExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderBy", propertyName, comparer);
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "OrderByDescending", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenBy", propertyName, comparer);
}
public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> query, string propertyName, IComparer<object> comparer = null)
{
return CallOrderedQueryable(query, "ThenByDescending", propertyName, comparer);
}
/// <summary>
/// Builds the Queryable functions using a TSource property name.
/// </summary>
public static IOrderedQueryable<T> CallOrderedQueryable<T>(this IQueryable<T> query, string methodName, string propertyName,
IComparer<object> comparer = null)
{
var param = Expression.Parameter(typeof(T), "x");
var body = propertyName.Split('.').Aggregate<string, Expression>(param, Expression.PropertyOrField);
return comparer != null
? (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param),
Expression.Constant(comparer)
)
)
: (IOrderedQueryable<T>)query.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
methodName,
new[] { typeof(T), body.Type },
query.Expression,
Expression.Lambda(body, param)
)
);
}
}
Creo que tendrías que usar la reflexión, y no estoy seguro de que puedas usar el reflejo en una expresión lambda ... bueno, casi con certeza no en Linq a SQL, pero tal vez al usar Linq en una lista o algo. – CodeRedick
@Telos: no hay ninguna razón para que no puedas usar la reflexión (o cualquier otra API) en una lambda. Si esto funciona o no si el código se evalúa como una expresión y se traduce a otra cosa (como LINQ-to-SQL, como usted sugiere) es otra cuestión completamente distinta. –
Es por eso que publiqué un comentario en lugar de una respuesta. ;) Mayormente acostumbrado a Linq2SQL ... – CodeRedick