Ordinamento usando il nome della proprietà come stringa

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

Domanda

Vorrei che la mia API Web fosse in grado di ordinare il suo output tramite un parametro stringa come questo:

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

Perché ho anche il supporto di paginazione (con skip e take ) nella mia API, vorrei che il parametro orderBy e descending venisse applicato direttamente alla query SQL, in modo che il risultato corretto provenga dal database.

Tuttavia, quando si esegue questa operazione, il codice può diventare molto difficile da gestire quando si cerca di far corrispondere i parametri per orderBy con le proprietà effettive delle classi che desidero ordinare utilizzando solo confronti tra stringhe.

Ho trovato una soluzione che dovrebbe funzionare con LINQ alle Entities e quindi anche con il nuovo EF7, tuttavia quando provo a compilare questo codice usando il nuovo Core CLR, ottengo il seguente messaggio:

Errore CS1503 Argomento 2: impossibile convertire da "System.Linq.Expressions.Expression>" a "stringa"

Il codice dalla soluzione che non riesce è il metodo OrderBy<T> :

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

Sembra che il nuovo Core CLR non supporti questo tentativo. C'è un altro modo per far funzionare la soluzione con il nuovo CLR? In caso negativo, quali altre alternative devo abilitare l'ordinamento utilizzando EF7 senza generare innumerevoli istruzioni if o switch per confrontare le stringhe di input con i nomi delle proprietà?

Risposta accettata

La soluzione dal tuo link utilizza un "Expression.Convert" che la maggior parte delle volte non funziona con LINQ alle Entities.

Ecco un metodo di estensione funzionante:

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 : sono il proprietario del progetto EF + su GitHub.

Puoi trovare altri metodi per ordinare per nome della proprietà nel mio repository: GitHub

  • OrderByDescending
  • ThenBy
  • ThenByDescending
  • AddOrAppendOrderBy
  • AddOrAppendOrderByDescending

EDIT : Rispondi alla sotto-domanda

È possibile ordinare le proprietà di navigazione usando qualcosa di simile, ad esempio un nome di proprietà "NavigationProperty.PropertyName"

Sì, puoi dividere la stringa e il loop per creare l'espressione con il percorso della proprietà o utilizzare un valutatore di espressioni reali.

Disclaimer : sono il proprietario del progetto Eval-Expressions.NET

Questa libreria ti consente di eseguire in modo dinamico tutti i metodi LINQ.

Vedi: LINQ dinamico

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


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é