Entity framework 使用反射排序

Entity framework ordering using reflection

我有一个用于排序的扩展方法,sortExpression 可以是 "Description" 或 "Description DESC" 之类的东西,它在相同 table:[=15= 的列上工作得很好]

 public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortExpression)
    {
        if (source == null)
            throw new ArgumentNullException("source");

        if (string.IsNullOrEmpty(sortExpression))
            return source;

        var parts = sortExpression.Split(' ');
        var isDescending = false;
        var propertyName = "";
        var type = typeof(T);

        if (parts.Length > 0 && parts[0] != "")
        {
            propertyName = parts[0];

            if (parts.Length > 1)
                isDescending = parts[1].ToLower().Contains("esc");

            var prop = type.GetProperty(propertyName);
            if (prop == null)
                throw new ArgumentException(string.Format("No property '{0}' on type '{1}'", propertyName, type.Name));

            var funcType = typeof(Func<,>)
                .MakeGenericType(type, prop.PropertyType);

            var lambdaBuilder = typeof(Expression)
                .GetMethods()
                .First(x => x.Name == "Lambda" && x.ContainsGenericParameters && x.GetParameters().Length == 2)
                .MakeGenericMethod(funcType);

            var parameter = Expression.Parameter(type);
            var propExpress = Expression.Property(parameter, prop);

            var sortLambda = lambdaBuilder
                .Invoke(null, new object[] { propExpress, new ParameterExpression[] { parameter } });

            var sorter = typeof(Queryable)
                .GetMethods()
                .FirstOrDefault(x => x.Name == (isDescending ? "OrderByDescending" : "OrderBy") && x.GetParameters().Length == 2)
                .MakeGenericMethod(new[] { type, prop.PropertyType });

            var result = (IQueryable<T>)sorter
                .Invoke(null, new object[] { source, sortLambda });
            return result;
        }

        return source;
    }

工作示例:

    var query = db.Audit.Include("AccessLevel").AsQueryable();
    query = query.OrderBy("Description");

请注意 "Description" 列存在于同一 table "Audit"。

我想做的是按关系中的列排序 table:

点赞

  var query = db.Audit.Include("AccessLevel").AsQueryable();
  query = query.OrderBy("AccessLevel.Name");

相当于:

query = query.OrderBy(o => o.AccessLevel.Name);

我的扩展方法需要进行哪些修改?

我用下面的代码解决了这个问题:

 public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
        {

                return ApplyOrder<T>(source, parts[0], "OrderBy");

        }
        public static IQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "OrderByDescending");
        }
        public static IQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "ThenBy");
        }
        public static IQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)
        {
            return ApplyOrder<T>(source, property, "ThenByDescending");
        }
        static IQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
        {

            if (source == null)
                throw new ArgumentNullException("source");

            if (string.IsNullOrEmpty(property))
                return source;


            string[] props = property.Split('.');
            Type type = typeof(T);
            ParameterExpression arg = Expression.Parameter(type, "x");
            Expression expr = arg;
            foreach (string prop in props)
            {
                // use reflection (not ComponentModel) to mirror LINQ
                PropertyInfo pi = type.GetProperty(prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }
            Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
            LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);

            object result = typeof(Queryable).GetMethods().Single(
                    method => method.Name == methodName
                            && method.IsGenericMethodDefinition
                            && method.GetGenericArguments().Length == 2
                            && method.GetParameters().Length == 2)
                    .MakeGenericMethod(typeof(T), type)
                    .Invoke(null, new object[] { source, lambda });
            return (IQueryable<T>)result;
        }