Wie kann ich OrderBy auf ein IQueryable anwenden, indem ich einen Stringspaltennamen in einer generischen Erweiterungsmethode verwende?

.net c# entity-framework expression-trees linq

Frage

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

Da der Typ für OrderBy nicht aus sortExpression abgeleitet werden kann, muss er zur Laufzeit wie folgt angegeben werden:

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

Oder

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

Ich glaube nicht, dass dies möglich ist, da TSortColumn nur zur Laufzeit ermittelt werden kann.

Gibt es einen Weg dahin?

Akzeptierte Antwort

Wir haben in einem LINQ to SQL-Projekt etwas ähnliches (nicht 100% gleich, aber ähnlich) gemacht. Hier ist der Code:

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

Wir haben nicht wirklich ein generisches verwendet, wir hatten eine bekannte Klasse, aber es sollte auf einem generischen funktionieren (ich habe den generischen Platzhalter dort platziert, wo er sein sollte).

Bearbeiten: Für absteigende Reihenfolge übergeben Sie OrderByDescending anstelle von "OrderBy":

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

Beliebte Antwort

Sie können auch Dynamic Linq verwenden

Info hier http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

C # hier herunterladen http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Dann fügen Sie einfach die Verwendung Linq.Dynamic; und Sie erhalten automatisch 2 zusätzliche Erweiterungsmethoden, die so verwendet werden können

return query.OrderBy("StringColumnName");



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum