【问题标题】:EF Core 3.1 Generated Expressions at Runtime all fail with unable to processes query on serverEF Core 3.1 在运行时生成的表达式都失败,无法处理服务器上的查询
【发布时间】:2020-05-16 08:30:04
【问题描述】:

过去我们可以使用这样的代码:

public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
{
    // LAMBDA: x => x.[PropertyName]
    var parameter = Expression.Parameter(typeof(TSource), "x");
    Expression property = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda(property, parameter);

    // REFLECTION: source.OrderBy(x => x.Property)
    var orderByMethod = typeof(Queryable).GetMethods().First(x => x.Name == "OrderBy" && x.GetParameters().Length == 2);
    var orderByGeneric = orderByMethod.MakeGenericMethod(typeof(TSource), property.Type);
    var result = orderByGeneric.Invoke(null, new object[] { source, lambda });

    return (IOrderedQueryable<TSource>)result;
}

按顺序进行,但现在在 EF Core 3.1 中失败

并且在 source.QueryBy(x => EF.Property(x, "Name")) 中使用会导致错误使用 EF.Property 错误,因此我不知道如何避免这些错误并且仍然在 IQueryable 上构建动态表达式尝试。

我做错了什么?

【问题讨论】:

  • 如果您还发布查询执行期间发生的实际异常消息会很有帮助

标签: linq entity-framework-core expression-trees


【解决方案1】:

你没有做错任何事 - EF Core “为你”做错了:-(

不确定您所说的“过去”是什么意思,但 EF Core 从一开始就存在一些他们所谓的“非编译器生成”表达式的问题,例如以下 SO 帖子

How to use inherited properties in EF Core expressions?

Why Linq "where" expression after Select gets evaluated locally when created through a generic method?

The LINQ expression could not be translated for base property

还有许多 GitHub 问题,例如

Building Filter and/or OrderBy via Expression on Intermediate type throws InvalidOpException #19087

貌似终于用Query: Match memberInfo in hierarchy for reducing MemberInitExpression #19182修复了,可惜没有包含在3.1中,所以要等年底5.0(换1行!)。

在此之前,您必须使用上述解决方法,例如使用以下 Expression.Property 替换(基本上是来自 How to use inherited properties in EF Core expressions? 的代码):

static MemberExpression Property(Expression expression, string propertyName)
{
    var propertyInfo = expression.Type.GetProperty(propertyName);
    if (propertyInfo.ReflectedType != propertyInfo.DeclaringType)
        propertyInfo = propertyInfo.DeclaringType.GetProperty(propertyName);
    return Expression.MakeMemberAccess(expression, propertyInfo);  
}

例如

var property = Property(propertyName);

应该解决问题。


不相关,但您也可以通过两种方式改进您的方法。

首先,您可以通过使用“Prop1.Prop2.Prop3”等点分隔字符串轻松添加对嵌套属性的支持

var property = propertyName.Split(".")
    .Aggregate((Expression)parameter, Property);

其次,您可以简单地将Expression.Call 发射到Queryable.OrderBy,而不是反射。

整个方法可能是这样的:

public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
{
    var parameter = Expression.Parameter(source.ElementType, "x");
    var property = propertyName.Split(".")
        .Aggregate((Expression)parameter, Property);
    var selector = Expression.Lambda(property, new[] { parameter });
    var expression = Expression.Call(typeof(Queryable), nameof(Queryable.OrderBy),
        new[] { source.ElementType, property.Type },
        new[] { source.Expression, Expression.Quote(selector) });
    return (IOrderedQueryable<TSource>)source.Provider.CreateQuery(expression);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 2017-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多