我正在尝试创建通用的 OrderBy (字段集合)方法,以在新的EF .Net Core 2.1中使用该方法,并设法编写以下代码:
public static Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetOrderByFunction(List<SortColumn> columns)
{
Type typeQueryable = typeof(IQueryable<TEntity>);
ParameterExpression argQueryable = Expression.Parameter(typeQueryable, "p");
LambdaExpression outerExpression = Expression.Lambda(argQueryable, argQueryable);
Type entityType = typeof(TEntity);
ParameterExpression arg = Expression.Parameter(entityType, "x");
Expression expr = arg;
Expression resultExp = null;
foreach (SortColumn sc in columns)
{
PropertyInfo pi = entityType.GetProperty(sc.FieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
Expression propertyExpr = Expression.Property(expr, pi);
Type propertyType = pi.PropertyType;
LambdaExpression lambdaExp = Expression.Lambda(propertyExpr, arg);
String methodName = string.Empty;
if (resultExp != null)
{
methodName = sc.Descending ? "ThenBy" : "ThenByDescending";
/// No generic method 'ThenBy' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments.
/// No type arguments should be provided if the method is non - generic.
Expression exp = Expression.Call(typeof(Queryable), methodName, new Type[] { entityType, propertyType }, outerExpression.Body, Expression.Quote(lambdaExp));
MethodInfo minfo = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(m => m.Name == methodName);
/// Method System.Linq.IOrderedQueryable`1
/// [TSource] OrderBy[TSource,TKey](System.Linq.IQueryable`1
/// [TSource],System.Linq.Expressions.Expression`1
/// [System.Func`2[TSource,TKey]]) is a generic method definition
/// Parameter name: method
resultExp = Expression.Call(minfo, exp, resultExp);
}
else
{
methodName = sc.Descending ? "OrderBy" : "OrderByDescending";
resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { entityType, propertyType }, outerExpression.Body, Expression.Quote(lambdaExp));
}
}
LambdaExpression orderedLambda = Expression.Lambda(resultExp, argQueryable);
return (Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)orderedLambda.Compile();
}
我的Sortcolumn
类仅保留字段名称和顺序方向。
public class SortColumn
{
public string FieldName { get; }
public bool Descending { get; }
public SortColumn(string fieldName, bool descending)
{
FieldName = fieldName;
Descending = descending;
}
}
当我的收藏集只有一个项目(例如ID或Description),但无法按多个字段进行排序时,此方法有效。
代码段中注释了我得到的错误:
类型'System.Linq.Queryable'上的通用方法'ThenBy'与提供的类型参数不兼容 和争论。 如果该方法是非通用的,则不应该提供任何类型参数。
这很奇怪,因为它对于OrderBy
命令可以正常工作。
但是,即使我通过了OrderBy
,也无法“加入”方法来组装一个唯一的表达式。我得到的错误是:
方法System.Linq.IOrderedQueryable'1 [TSource] OrderBy [TSource,TKey](System.Linq.IQueryable'1 [TSource],System.Linq.Expressions.Expression'1 [System.Func'2 [TSource,TKey]])是通用方法定义 参数名称:方法
我尝试过的事情:
将typeof(Queryable)
更改为使用Enumerable
或EnumerableQuery
,甚至使用List,Use invoke等。
我的目标是动态传递字段列表,以便为我的域对象订购GetAll()方法,构建一个委托函数可以给我类似的东西
var test = new List<TEntity>();
test.OrderBy(x => x.Id).ThenByDescending(x => x.Description);
答案 0 :(得分:1)
我觉得您使所有事情变得过于复杂了:
// Or IEnumerable<SortColumn> columns
public static Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> GetOrderByFunction<TEntity>(params SortColumn[] columns)
{
Type typeQueryable = typeof(IQueryable<TEntity>);
ParameterExpression argQueryable = Expression.Parameter(typeQueryable, "p");
Type entityType = typeof(TEntity);
ParameterExpression arg = Expression.Parameter(entityType, "x");
Expression resultExp = argQueryable;
bool first = true;
foreach (SortColumn sc in columns)
{
PropertyInfo pi = entityType.GetProperty(sc.FieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
Expression propertyExpr = Expression.Property(arg, pi);
Type propertyType = pi.PropertyType;
LambdaExpression lambdaExp = Expression.Lambda(propertyExpr, arg);
string methodName;
if (first)
{
first = false;
methodName = sc.Descending ? "OrderBy" : "OrderByDescending";
}
else
{
methodName = sc.Descending ? "ThenBy" : "ThenByDescending";
}
resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { entityType, propertyType }, resultExp, Expression.Quote(lambdaExp));
}
// Case empty columns: simply append a .OrderBy(x => true)
if (first)
{
LambdaExpression lambdaExp = Expression.Lambda(Expression.Constant(true), arg);
resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { entityType, typeof(bool) }, resultExp, Expression.Quote(lambdaExp));
}
LambdaExpression orderedLambda = Expression.Lambda(resultExp, argQueryable);
return (Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>)orderedLambda.Compile();
}
我要补充一点,即调用FieldName
实际上是PropertyName
有点...误导:-)
请注意,我添加了columns
为空的情况:这是因为您返回了IOrderedQueryable
,因此必须始终存在排序。