【问题标题】:Entity Framework OrderBy on field from projection实体框架 OrderBy 来自投影的字段
【发布时间】:2015-06-17 13:44:20
【问题描述】:

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

要求:

  1. 用户应该能够对任何列进行排序;
  2. 该列可能来自实体或投影类;
  3. 程序员决定是返回相同的源实体还是投影。

由于 (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&lt;SampleDTO&gt;():

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

我试过projected.OfType&lt;SampleDTO&gt;():

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

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

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

我的实体和预测:

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&lt;Func&lt;Sample, SampleDTO&gt;&gt;,而不是Expression&lt;Func&lt;Sample, Sample&gt;&gt;。这会使要求 (3) 无效,并且会破坏我现有的大部分代码。

PS:我正在考虑使用 Microsoft Dynamic LINQ 库,但为了得到答案,我期待知道到底发生了什么。

【问题讨论】:

标签: c# linq entity-framework dto


【解决方案1】:

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

    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);
    }

【讨论】:

  • T 是样本,那么它会失败说“描述”没有在该类型上定义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多