Tri en utilisant le nom de la propriété comme chaîne

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

Question

J'aimerais que mon API Web puisse trier sa sortie par un paramètre de chaîne tel que celui-ci:

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

orderBy ma API take également en charge la pagination (avec skip et take ), je souhaite que les paramètres orderBy et descending soient appliqués directement à la requête SQL, afin que le résultat correct provienne de la base de données.

Cependant, lorsque vous faites cela, le code peut devenir très difficile à gérer lorsque vous essayez de faire correspondre les paramètres de orderBy aux propriétés réelles des classes que je souhaite trier en utilisant simplement des comparaisons de chaînes.

J'ai trouvé une solution censée fonctionner avec LINQ to Entities et donc également avec le nouvel EF7. Toutefois, lorsque j'essaie de compiler ce code à l'aide du nouveau Core CLR, le message suivant s'affiche:

Erreur CS1503 Argument 2: impossible de convertir 'System.Linq.Expressions.Expression>' en 'chaîne'

Le code de la solution qui échoue est la OrderBy<T> :

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

Il semble que le nouveau Core CLR ne supporte pas cette tentative. Existe-t-il un autre moyen de faire en sorte que la solution fonctionne avec le nouveau CLR? Si non, quelles autres alternatives dois-je activer pour activer le tri à l'aide de EF7 sans entraîner d'innombrables instructions if ou switch pour comparer les chaînes d'entrée aux noms de propriété?

Réponse acceptée

La solution de votre lien utilise un "Expression.Convert" qui, la plupart du temps, ne fonctionne pas avec LINQ to Entities.

Voici une méthode d'extension qui fonctionne:

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

Disclaimer : Je suis le propriétaire du projet EF + sur GitHub.

Vous pouvez trouver d'autres méthodes pour commander par nom de propriété dans mon référentiel: GitHub

  • OrderByDescending
  • Puis par
  • AlorsByDescending
  • AddOrAppendOrderBy
  • AddOrAppendOrderByDescending

EDIT : répondre à la sous-question

Est-il possible de trier les propriétés de navigation en utilisant quelque chose comme ceci, par exemple un nom de propriété "NavigationProperty.PropertyName"

Oui, vous pouvez fractionner la chaîne et la boucle pour créer l'expression avec la propriété path ou utiliser un évaluateur d'expression réel.

Disclaimer : Je suis le propriétaire du projet Eval-Expressions.NET

Cette bibliothèque vous permet d'exécuter toutes les méthodes LINQ de manière dynamique.

Voir: LINQ Dynamic

var result = list.OrderByDynamic(x => "NavigationProperty.PropertyName");


Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi