式を受け取るIQueryable.OrderBy拡張機能を持っている/知っている人はいますか(たとえば、Reflectionによって取得されます)?関数は次のようになると思います。
public static IQueryable<TEntity> OrderBy<TEntity>
(this IQueryable<TEntity> source, Expression sortExpression)
式はExpression<Func<TEntity, T>>
、TEntityがソートされているのと同じオブジェクトであり、Tが新しいIQueryableを作成するために決定する必要があるタイプであると想定されます。
次のようなDynamicLinqを含む、文字列を受け取る拡張機能の例をたくさん見つけました。
public static IQueryable<TEntity> OrderBy<TEntity>(
this IQueryable<TEntity> source, string sortExpression)
文字列を取得し、Reflectionを使用して問題のオブジェクトから型を検索できる場合は、式を取得して、式のすぐそこにある値型を取得することもできるはずです。
以下は、私がこれを欲しがっている理由の詳細な説明です。あなたがこれを必要とするかもしれないし、必要としないかもしれません。
並べ替える複雑なレコードのリストがかなりたくさんあります。リストが非常に長いので、データベース側でソートを行うことを好みます。より複雑なプロパティを処理するために、次のような並べ替え機能を提供する式を作成しました。
if (model.sortExpression == "PlannedValue")
{
Expression<Func<BDopp, decimal>> sorter = BDopp.PlannedValueSorter;
if (model.sortDirection == "DESC")
opps = opps.OrderByDescending(sorter).AsQueryable();
else
opps = opps.OrderBy(sorter).AsQueryable();
}
BDOpp.PlannedValueSorterは、オブジェクトから静的式を取得します。これにより、oppsなしで並べ替えを実行できます。タイプはIQueryableです。
public static Expression<Func<BDopp, decimal>> PlannedValueSorter
{
get
{
return z => z.BudgetSchedules
.Where(s => s.Type == 1)
.Sum(s => s.Value * s.Workshare * z.valueFactor / 100 / 100);
}
}
単純なプロパティの並べ替えは、文字列として渡されたプロパティの名前に基づいて式を作成するためにReflectionを使用するExtensionメソッドを使用して行われます。
これはうまく機能しますが、複雑なタイプの場合でも、分岐ロジックが必要であり、そうはしません。私がやりたいのは、式を含む静的プロパティをチェックしてから、それを適用することです。私はこのような表現を得ることができます:
PropertyInfo info = typeof(BDopp).GetProperty(model.sortExpression + "Sorter",
BindingFlags.Static | BindingFlags.Public);
Expression expr = (Expression)info.GetValue(null, null);
PlannedValueプロパティの場合、これにより、PlannedValueSorterで並べ替えられた式が取得されます。これは、すでに機能していることがわかっています。
アップデート:
さまざまな掘り下げによって、私はある程度の進歩があると思います。
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source,
Expression<Func<TEntity, dynamic>> sortExpression)
{
var unary = sortExpression.Body as UnaryExpression;
Type actualExpressionType = unary.Operand.Type;
actualExpressionTypeは、実際には式の戻り型です(この特定のプロパティの場合、10進数です)。
残念ながら、私はほとんど試行錯誤を繰り返しています。これがどのように機能するかについてまだ頭を悩ませていないため、このようにクエリを更新しようとしても機能しません。
MethodCallExpression resultExp = Expression.Call(typeof(Queryable),
"OrderBy",
new Type[] { typeof(TEntity), actualExpressionType },
source.Expression, sortExpression);
return source.Provider.CreateQuery<TEntity>(resultExp);
コンパイルは正常ですが、実行時に次のエラーがスローされます。
タイプ'System.Linq.Queryable'のジェネリックメソッド'OrderBy'は、提供されたタイプ引数および引数と互換性がありません。メソッドがジェネリックでない場合は、型引数を指定しないでください。