有没有人知道/知道带有表达式的 IQueryable.OrderBy 扩展名(例如,通过反射检索)?我相信这个函数看起来像这样:
public static IQueryable<TEntity> OrderBy<TEntity>
(this IQueryable<TEntity> source, Expression sortExpression)
将假定表达式是Expression<Func<TEntity, T>>
其中 TEntity 是被排序的同一对象,而 T 是需要确定的类型才能创建新的 IQueryable。
我发现了许多采用字符串的扩展示例,包括 Dynamic Linq,如下所示:
public static IQueryable<TEntity> OrderBy<TEntity>(
this IQueryable<TEntity> source, string sortExpression)
如果可以获取字符串并使用反射从相关对象中查找类型,那么也应该可以获取表达式,并获取表达式中的值类型。
以下是我为什么想要这个的详细解释,你可能需要也可能不需要。
我有一个相当大的复杂记录列表要排序。因为列表很长,我更喜欢在数据库端进行排序。为了处理更复杂的属性,我创建了提供排序功能的表达式,如下所示:
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);
}
}
简单属性的排序是使用扩展方法完成的,这些方法使用反射来构建基于作为字符串传递的属性名称的表达式。
这很好用,但是对于复杂类型,我仍然需要分支逻辑,我宁愿不这样做。我宁愿检查包含表达式的静态属性,然后简单地应用它。我可以得到这样的表达:
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 实际上是 Expression 的返回类型(对于这个特定的属性,它是十进制)。
不幸的是,我主要是通过反复试验来工作,因为我还没有完全了解这一切是如何工作的,所以我尝试像这样更新查询是行不通的:
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”与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。