Ordenar usando nombre de propiedad como cadena

asp.net asp.net-core c# entity-framework-core linq

Pregunta

Me gustaría que mi API web pueda ordenar su salida por un parámetro de cadena como este:

http://myapi.com/api/people?skip=0&take=50&orderBy=lastName&descending=true .

Como también tengo soporte de paginación (con skip y take ) en mi API, me gustaría que los parámetros orderBy y descending se apliquen directamente a la consulta SQL, de modo que el resultado correcto provenga de la base de datos.

Sin embargo, al hacer esto, el código puede ser muy difícil de administrar cuando se trata de hacer coincidir los parámetros de orderBy con las propiedades reales de las clases que deseo clasificar simplemente utilizando comparaciones de cadenas.

He encontrado una solución que se supone que funciona con LINQ para Entidades y, por lo tanto, también con el nuevo EF7, sin embargo, cuando intento compilar este código utilizando el nuevo Core CLR, recibo el siguiente mensaje:

Error CS1503 Argumento 2: no se puede convertir desde 'System.Linq.Expressions.Expression>' a 'cadena'

El código de la solución que falla es el OrderBy<T> :

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
{
    return source.OrderBy(ToLambda<T>(propertyName));
}

Parece que el nuevo Core CLR no admite este intento. ¿Hay otra manera de conseguir que la solución funcione con el nuevo CLR? Si no, ¿qué otras alternativas tengo para habilitar la clasificación utilizando EF7 sin que resulte en innumerables sentencias if o switch para comparar las cadenas de entrada con los nombres de las propiedades?

Respuesta aceptada

La solución de su enlace utiliza un "Expression.Convert" que la mayoría de las veces no funciona con LINQ to Entities.

Aquí hay un método de extensión de trabajo:

public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
{
    // LAMBDA: x => x.[PropertyName]
    var parameter = Expression.Parameter(typeof(TSource), "x");
    Expression property = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda(property, parameter);

    // REFLECTION: source.OrderBy(x => x.Property)
    var orderByMethod = typeof(Queryable).GetMethods().First(x => x.Name == "OrderBy" && x.GetParameters().Length == 2);
    var orderByGeneric = orderByMethod.MakeGenericMethod(typeof(TSource), property.Type);
    var result = orderByGeneric.Invoke(null, new object[] { source, lambda });

    return (IOrderedQueryable<TSource>)result;
}

Descargo de responsabilidad : soy el propietario del proyecto EF + en GitHub.

Puede encontrar otros métodos para ordenar por nombre de propiedad en mi repositorio: GitHub

  • OrderByDescending
  • Entonces por
  • ThenByDescending
  • AddOrAppendOrderBy
  • AddOrAppendOrderByDescending

EDIT : respuesta sub-pregunta

Es posible ordenar las propiedades de navegación utilizando algo como esto, por ejemplo, un nombre de propiedad "NavigationProperty.PropertyName"

Sí, puede dividir la cadena y el bucle para crear la expresión con la ruta de la propiedad o usar un evaluador de expresión real.

Descargo de responsabilidad : soy el propietario del proyecto Eval-Expressions.NET

Esta biblioteca le permite ejecutar todos los métodos LINQ dinámicamente.

Ver: LINQ Dynamic

public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
{
    // LAMBDA: x => x.[PropertyName]
    var parameter = Expression.Parameter(typeof(TSource), "x");
    Expression property = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda(property, parameter);

    // REFLECTION: source.OrderBy(x => x.Property)
    var orderByMethod = typeof(Queryable).GetMethods().First(x => x.Name == "OrderBy" && x.GetParameters().Length == 2);
    var orderByGeneric = orderByMethod.MakeGenericMethod(typeof(TSource), property.Type);
    var result = orderByGeneric.Invoke(null, new object[] { source, lambda });

    return (IOrderedQueryable<TSource>)result;
}



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué