实体框架OrderBy on投影领域

时间:2015-06-17 13:44:21

标签: c# linq entity-framework dto

我想对仅在运行时已知的字段进行排序,并且该字段可以在select子句内构建。

要求:

  1. 用户应该可以对任何列进行排序;
  2. 该列可能来自实体或投影类;
  3. 程序员决定是否要返回相同的源实体或投影。
  4. 由于(3),直接实现不会从投影类中找到一个字段,因为我有一个静态类型的基类/实体类型。然后我开始改变代码来考虑结果类型。

    我觉得这只是静态打字妨碍了,这在这里并没有真正帮助。遗憾的是IQueryable<dynamic>不起作用。

    示例代码(为简洁起见省略详细信息):

    void Main()
    {
        using (var db = new MyContext())
        {
            var original = db.Set<Sample>();
    
            // requirement (3), static type Sample, dynamic type SampleDTO
            Expression<Func<Sample, Sample>> fn = item => new SampleDTO() { Description = "Value: " + item.Name};
            var projected = original.Select(fn);
    
            // requirements (1) and (2)
            var ordered = OrderBy_Default<Sample, SampleDTO>(projected, "Description");
            ordered.Dump();
        }
    }
    
    private IQueryable<T> OrderBy_Default<T, TProject>(IQueryable<T> source, string ordering)
    {
      var type = source.ElementType;
      var resultType = type;
      var property = resultType.GetProperty(ordering, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
      var parameter = Expression.Parameter(resultType, "p");
      var propertyAccess = Expression.MakeMemberAccess(parameter, property);
      var orderByExp = Expression.Lambda(propertyAccess, parameter);
      MethodCallExpression resultExp = Expression.Call(typeof(Queryable),
          "OrderBy",
          new Type[] { type, property.PropertyType },
          source.Expression, Expression.Quote(orderByExp));
      return source.Provider.CreateQuery<T>(resultExp);
    }
    

    前面的代码产生了这个错误:

      

    类型'Queryable'上没有泛型方法'OrderBy'与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

    我试过projected.Cast<SampleDTO>()

      

    无法将“Sample”类型转换为“UserQuery + SampleDTO”类型。 LINQ to Entities仅支持转换EDM原语或枚举类型。

    我试过projected.OfType<SampleDTO>()

      

    'UserQuery + SampleDTO'不是类型过滤操作的有效元数据类型。类型过滤仅对实体类型和复杂类型有效。

    Cast()OfType()适用于L2O,但不适用于L2EF。

    SampleDTO添加到实体模型当然不是答案(尽管已经尝试过,但为了解它是如何工作的。)

    我的实体&amp;突起:

    public class Sample
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    public class SampleDTO: Sample
    {
        public string Description { get; set; }
    }
    

    我让SampleDTO继承自Sample,它有点帮助。这不是一个要求,这是一个方便的问题。

    一些可能的答案:

    而不是Expression<Func<Sample, Sample>>我可以拥有Expression<Func<Sample, SampleDTO>>。这使得require(3)无效,并且会破坏我现有的大部分代码。

    PS:我正在考虑使用Microsoft Dynamic LINQ库,但为了解决这个问题,我很期待知道它到底发生了什么。

1 个答案:

答案 0 :(得分:0)

这对我有用,如果我正确理解你的问题,但我感觉我错过了什么

    public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering)
    {
        var type = typeof(T);
        var property = type.GetProperty(ordering);
        var parameter = Expression.Parameter(type);
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);
        MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
        return source.Provider.CreateQuery<T>(resultExp);
    }