LINQ表达式无法转换为基本属性

时间:2019-03-22 07:46:54

标签: c# .net-core entity-framework-core

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

filtered_list = [i['id'] for i in  filter(lambda item: item['views'] operation_map[operator] target_value, list1)]

我使用的是entityframework core 2.2,但是非常有趣的事情是,如果我只写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); } ,那么它就可以正常工作了,所以我的自定义实现必须有一些东西

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

source.OrderBy(x=>x.someBaseField)

1 个答案:

答案 0 :(得分:5)

我以前见过类似的东西。编译器生成和手动表达式之间的唯一区别是ReflectedType的{​​{1}}属性-在编译器生成的代码中,它与PropertyInfo相同,在本例中为基类,而在通过DeclaringType获得的PropertyInfo是用于获取它的派生类型。

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

type.GetProperty

或使用像这样的帮助方法

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

为了支持嵌套属性,我将添加以下帮助器

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

然后使用

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

有问题的方法中