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.
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));
and then use
var propertyAccess = Property(param, orderByProperty);
and
new Type[] { type, orderByExpression.ReturnType },
inside the method in question.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…