无法为基本属性翻译 LINQ 表达式 [英] The LINQ expression could not be translated for base property

查看:17
本文介绍了无法为基本属性翻译 LINQ 表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有自定义的 OrderBy 实现,它只适用于没有继承的类型,如果我想从基本类型的字段排序,我得到了 LINQ 表达式无法翻译

I have custom OrderBy implementation, it only works for types without inheritance, if I want order by field from base type I got The LINQ expression could not be translated

public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }

    if (string.IsNullOrEmpty(orderByProperty))
    {
        throw new ArgumentNullException(nameof(orderByProperty));
    }

    var command = desc ? "OrderByDescending" : "OrderBy";

    var type = typeof(TEntity);

    var param = Expression.Parameter(type, "p");
    var property = type.GetProperty(orderByProperty);
    var propertyAccess = Expression.MakeMemberAccess(param, property);
    var orderByExpression = Expression.Lambda(propertyAccess, param);
    var resultExpression = Expression.Call(
            typeof(Queryable),
            command,
            new Type[] { type, property.PropertyType },
            source.Expression,
            Expression.Quote(orderByExpression));
    return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery(resultExpression);
}

我使用的是 entityframework 核心 2.2,但非常有趣的是,如果我只编写 source.OrderBy(x=>x.someBaseField) 那么它可以正常工作,因此必须通过我的自定义实现的东西

I am using entityframework core 2.2 but the very interesting thigs is that if I write just source.OrderBy(x=>x.someBaseField) then it works without any problem, so there must by something with my custom implementation

在错误日志中,我也得到了翻译后的查询,它看起来像这样,有趣的是结尾部分

In error log I got also the translated query and it looks like this, intereresting is end part

orderby new SomeType() {NewField = [entity].DbField, Id = [entity].Id}.Id desc

orderByExpression.Body {p => p.Id}

resultExpression

.Call System.Linq.Queryable.OrderByDescending(
    .Call System.Linq.Queryable.Select(
        .Call System.Linq.Queryable.Where(
            .Call System.Linq.Queryable.Where(
                .Constant<Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[MyTypeView]>(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[MyTypeView]),
                '(.Lambda #Lambda1<System.Func`2[MyTypeView,System.Boolean]>)),
            '(.Lambda #Lambda2<System.Func`2[MyTypeView,System.Boolean]>)),
        '(.Lambda #Lambda3<System.Func`2[MyTypeView, MyTypeResult]>))
    ,
    '(.Lambda #Lambda4<System.Func`2[MyTypeResult,System.Guid]>))

推荐答案

我以前见过这样的事情.编译器生成和手动表达式之间的唯一区别是 PropertyInfoReflectedType 属性 - 在编译器生成的代码中,它与 DeclaringType 相同,在本例是基类,而在通过type.GetProperty获取的PropertyInfo中,它是用于获取它的派生类型.

I've seen something like this before. The only difference between compiler generated and manual expression is the ReflectedType property of the PropertyInfo - in compiler generated code it's the same as DeclaringType, which in this case is the base class, while in the PropertyInfo obtained via type.GetProperty it is the derived type used to obtain it.

由于某些未知原因(可能是错误),这让 EF Core 感到困惑.解决方法是将代码更改如下:

For some unknown reason (probably a bug) this is confusing EF Core. The workaround is to change the code as follows:

var property = type.GetProperty(orderByProperty);
if (property.DeclaringType != property.ReflectedType)
    property = property.DeclaringType.GetProperty(property.Name);

或者使用这样的辅助方法

or use a helper method like this

static PropertyInfo GetProperty(Type type, string name)
{
    for (; type != null; type = type.BaseType)
    {
        var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
        if (property != null) return property;
    }
    return null;
}

<小时>

为了支持嵌套属性,我会添加以下助手


In order to support nested properties, I would add the following helpers

static Expression Property(Expression target, string name) =>
    name.Split('.').Aggregate(target, SimpleProperty);

static Expression SimpleProperty(Expression target, string name) =>
    Expression.MakeMemberAccess(target, GetProperty(target.Type, name));

然后使用

var propertyAccess = Property(param, orderByProperty);

new Type[] { type, orderByExpression.ReturnType },

在所讨论的方法中.

这篇关于无法为基本属性翻译 LINQ 表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆