类型'System.Linq.Queryable'上没有通用方法'ThenBy' [英] No generic method 'ThenBy' on type 'System.Linq.Queryable'

查看:81
本文介绍了类型'System.Linq.Queryable'上没有通用方法'ThenBy'的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建通用的 OrderBy (字段集合)方法以在新的EF .Net Core 2.1中使用,并设法编写以下代码:

I'm trying to create a generic OrderBy(fields collection) method to use in a new EF .Net Core 2.1 and managed to write the below code:

 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类仅保留字段名称和顺序方向.

My Sortcolumn class just hold the field name and order direction.

public class SortColumn
{
    public string FieldName { get; }
    public bool Descending { get; }

    public SortColumn(string fieldName, bool descending)
    {
        FieldName = fieldName;
        Descending = descending;
    }
}

当我的收藏集只有一个项目(例如Id或Description),但无法按多个字段进行排序时,此方法有效.

It works when my collection has only a single item like Id or Description but fails to sort by more than one field.

我的错误在代码段中进行了评论:

The errors I got are commented in the snippet:

类型'System.Linq.Queryable'上的通用方法'ThenBy'与提供的类型参数不兼容 和争论. 如果该方法是非通用的,则不应该提供任何类型参数.

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.

这很奇怪,因为它对于OrderBy命令可以正常工作. 但是,即使我通过了OrderBy,也无法加入"这些方法来组装一个唯一的表达式.我得到的错误是:

It's strange because it works fine for the OrderBy command. But even if I pass the OrderBy I was unable to "join" the methods to assemble a unique expression. The error I got is:

方法System.Linq.IOrderedQueryable'1 [TSource] OrderBy [TSource,TKey](System.Linq.IQueryable'1 [TSource],System.Linq.Expressions.Expression'1 [System.Func'2 [TSource,TKey]])是通用方法定义 参数名称:方​​法

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

我尝试过的事情: 更改typeof(Queryable)以使用EnumerableEnumerableQuery甚至是列表,使用调用等.

Things I tried: Change typeof(Queryable) to use Enumerable or EnumerableQuery or even List, Use invoke, etc.

我的目标是动态地传递字段列表,以便为我的域对象排序我的GetAll()方法,构建一个委托函数可以给我类似的东西

My goal is to dynamicaly pass a list of fields to order my GetAll() methods for my domain objects building a delegate function can give me something like:

            var test = new List<TEntity>();
            test.OrderBy(x => x.Id).ThenByDescending(x => x.Description);

推荐答案

我觉得您使所有事情变得过于复杂了:

I feel you are overcomplicating everything:

// 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有点...误导:-)

I'll add that calling FieldName what is really a PropertyName is a little... misleading :-)

请注意,我添加了columns为空的情况:这是因为您返回了IOrderedQueryable,因此必须始终存在排序.

Note that I've added the case for when columns is empty: this because you return a IOrderedQueryable, so an ordering must always be present.

这篇关于类型'System.Linq.Queryable'上没有通用方法'ThenBy'的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆