1. ホーム
  2. c#

[解決済み] 汎用拡張メソッド内で文字列のカラム名を使用して、IQueryable に OrderBy を適用するにはどうすればよいですか?

2023-03-26 10:57:16

質問

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

OrderByの型はsortExpressionから推論されないので、実行時にこのように指定する必要があります。

var sortExpression = Expression.Lambda<T, TSortColumn>(body, param);

または

return query.OrderBy<T, TSortColumn>(sortExpression);

しかし、TSortColumnは実行時にしか決定できないので、これは不可能だと思います。

これを回避する方法はありますか?

どのように解決するのですか?

LINQ to SQL プロジェクトで、似たようなこと (100%同じではありませんが、似ています) をしました。以下はそのコードです。

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

実際にはジェネリックを使わず、既知のクラスを使っていましたが、ジェネリックでも動くはずです(ジェネリックのプレースホルダーをあるべき場所に置きました)。

編集してください。 降順にする場合は OrderByDescending の代わりにを渡してください。

MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));