过滤实体,然后对动态字段进行排序

时间:2011-04-20 15:40:36

标签: c# linq entity-framework sorting

我正在尝试首先过滤一组产品,然后订购它们

  (repository.GetAllProducts()
     .Where(x=>x.Naam.Contains("filter")) as ObjectQuery<Product>)
     .FunkyOrder<Product>(sortfield,sortdirection)

使用Extension方法:

 public  static IEnumerable<T> FunkyOrder<T>(this ObjectQuery<T> input, string fieldname = "Id", string sortdirection = "asc")
        {            
            switch (sortdirection)
            {
                case "dsc":
                case "desc":
                    return input.OrderBy("it." + fieldname + " DESC");
                default:
                    return input.OrderBy("it." + fieldname);

            }
        }

(我的Repository的GetAllProducts()返回一个IEnumerable

这个FunkyOrder方法应该可以工作但是 - 作为ObjectQuery - cast返回NULL

我只能将FunkyOrder与ObjectQuery一起使用,因为这似乎是唯一支持那些“it.FieldName”查询的东西。

如果我将 - as - notation更改为常规演员,我会得到:

 Unable to cast object of type 'WhereEnumerableIterator`1[MySecretNameSpace.Product]' to type 'System.Data.Objects.ObjectQuery`1[MySecretNameSpace.Product]'.

有没有办法让这项工作或者我会被迫在过滤前使用排序,或者为我的排序编写一个带有lambda表达式的巨型开关?

3 个答案:

答案 0 :(得分:7)

这实际上是一个试图解决的巨大头痛;但最终,它实际上很容易通过一些hackishness和反思完成:

public class Program
{
    public class SomeClass
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    static void Main(string[] args)
    {
        List<SomeClass> sample = new List<SomeClass>
        {
            new SomeClass { Id = 4, Name = "ABC" },
            new SomeClass { Id = 1, Name = "XYZ" },
            new SomeClass { Id = 2, Name = "JKL" }
        };

        var result = sample.OrderByDynamic("Name", OrderDirection.Ascending).ToList();

        result.ForEach(x => Console.WriteLine("Id: " + x.Id + " | Name: " + x.Name));

        Console.ReadKey();
    }
}

public enum OrderDirection
{
    Ascending,
    Descending
}

public static class LinqExtensions
{
    public static IEnumerable<T> OrderByDynamic<T>(this IEnumerable<T> source, string propertyName, OrderDirection direction = OrderDirection.Ascending)
    {
        if(direction == OrderDirection.Ascending)
            return source.OrderBy(x => x.GetType().GetProperty(propertyName).GetValue(x, null));
        else
            return source.OrderByDescending(x => x.GetType().GetProperty(propertyName).GetValue(x, null));
    }
}

这个例子在测试情况下对我有用;我可以提供属性名称,并指定排序方向,它工作得很好。只需像这样打电话:

yourEnumerable.OrderByDynamic("YourPropertyName");
yourEnumerable.OrderByDynamic("YourPropertyName", OrderDirection.Descending);

享受!

答案 1 :(得分:2)

我会将你的FunkyOrder方法更改为IEnumerable并通过动态创建一个表达式实现动态排序

public static IEnumerable<T> FunkyOrder<T, TResult>(this IEnumerable<T> input, string fieldname = "Id", string sortdirection = "asc")
{
 ParameterExpresssion parameter = Expression.Parameter(typeof(T), "p");
 Expression property = Expression.PropertyOrField(parameter, fieldname);

 var lambda = Expression.Lambda<Func<T, TResult>>(property, parameter)

 if(sortdirection == "asc")
 {
  return input.OrderBy(lambda.Compile());
 }
 else
 {
  return input.OrderByDescending(lambda.Complile());
 }
}

您将不再需要转换为ObjectQuery

答案 2 :(得分:1)

您可以使用Dynamic Linq进行动态过滤和排序。这个小型库(只有一个源文件)包含IQueryable<T>的扩展方法,如:

public static IQueryable<T> Where<T>(this IQueryable<T> source,
    string predicate, params object[] values)

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source,
    string ordering, params object[] values)

//...and more like GroupBy, Select

您对IEnumerable的查询可以写成:

repository.GetAllProducts().AsQueryable()
    .Where(x => x.Naam.Contains("filter"))
    .OrderBy("FieldName desc")

库实现了执行这些动态查询所需的所有反射代码。