无法翻译 LINQ 表达式 'DbSet<Person>() .Where(p => p.Id % 2 == 0 ? Even : Odd == Even)'
The LINQ expression 'DbSet<Person>() .Where(p => p.Id % 2 == 0 ? Even : Odd == Even)' could not be translated
我有一个 class 人,它有一些聚合值,例如如果 ID 是偶数或奇数。
public class Person
{
public int Id { get; set; }
// ... some properties
public static Expression<Func<Person, NumberType>> NumberType
{
get
{
return p => ((p.Id % 2 == 0)
? Shared.NumberType.Even
: Shared.NumberType.Odd);
}
}
}
public enum NumberType
{
Even = 0,
Odd = 1
}
现在如果我尝试让我的人拥有偶数 ID
// this is DbSet<Person>
var people = dbContext.People.AsQueryable();
// this alone works
people = people.Where(p => ((p.Id % 2 == 0) ? Shared.NumberType.Even : Shared.NumberType.Odd) == Shared.NumberType.Even);
// this should do exactly the same as above but results in the following error as soon as the queryable is evaluated
var body = Expression.MakeBinary(ExpressionType.Equal, Person.LocalNumberType.Body, Expression.Constant(Shared.NumberType.Even));
people = people.Where(Expression.Lambda<Func<Person, bool>>(body, Expression.Parameter(typeof(Person), "p")));
// exception thrown here
var evenCount = people.Count();
处理请求时发生未处理的异常。
InvalidOperationException:LINQ 表达式 'DbSet()
.Where(p => (int)p.Id % 2 == 0 ? Even : Odd == 0)
.Where(p => p.Id % 2 == 0 ? Even : Odd == Even)' 无法翻译。要么以可以翻译的形式重写查询,要么通过插入对 'AsEnumerable'、'AsAsyncEnumerable'、'ToList' 或 'ToListAsync' 的调用显式切换到客户端评估。有关详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2101038。
// FUNFACT, ordering by the Expression works
var orderByExp = (typeof(Person).GetProperty("NumberType")!.GetValue(null, null) as LambdaExpression);
people = people.Provider.CreateQuery<Person>(Expression.Call(
typeof(Queryable),
"orderBy",
new Type[] {
typeof(Person),
orderByExp.ReturnType
},
people.Expression,
Expression.Quote(orderByExp)));
lambda 表达式中的参数表达式是按实例标识的,而不是像你想象的那样按名称标识。所以这里
var body = Expression.MakeBinary(ExpressionType.Equal, Person.LocalNumberType.Body, Expression.Constant(Shared.NumberType.Even));
people = people.Where(Expression.Lambda<Func<Person, bool>>(body, Expression.Parameter(typeof(Person), "p")));
正文绑定到源 Person.NumberType
表达式参数,但是您在新的 lambda 表达式中使用它,参数 不同(事件虽然相同类型和名称)。
一种可能的解决方案是重用原始参数,例如
var source = Person.LocalNumberType;
var body = Expression.Equal(source.Body, Expression.Constant(Shared.NumberType.Even));
var predicate = Expression.Lambda<Func<Person, bool>>(body, source.Parameters);
people = people.Where(predicate);
我有一个 class 人,它有一些聚合值,例如如果 ID 是偶数或奇数。
public class Person
{
public int Id { get; set; }
// ... some properties
public static Expression<Func<Person, NumberType>> NumberType
{
get
{
return p => ((p.Id % 2 == 0)
? Shared.NumberType.Even
: Shared.NumberType.Odd);
}
}
}
public enum NumberType
{
Even = 0,
Odd = 1
}
现在如果我尝试让我的人拥有偶数 ID
// this is DbSet<Person>
var people = dbContext.People.AsQueryable();
// this alone works
people = people.Where(p => ((p.Id % 2 == 0) ? Shared.NumberType.Even : Shared.NumberType.Odd) == Shared.NumberType.Even);
// this should do exactly the same as above but results in the following error as soon as the queryable is evaluated
var body = Expression.MakeBinary(ExpressionType.Equal, Person.LocalNumberType.Body, Expression.Constant(Shared.NumberType.Even));
people = people.Where(Expression.Lambda<Func<Person, bool>>(body, Expression.Parameter(typeof(Person), "p")));
// exception thrown here
var evenCount = people.Count();
// FUNFACT, ordering by the Expression works
var orderByExp = (typeof(Person).GetProperty("NumberType")!.GetValue(null, null) as LambdaExpression);
people = people.Provider.CreateQuery<Person>(Expression.Call(
typeof(Queryable),
"orderBy",
new Type[] {
typeof(Person),
orderByExp.ReturnType
},
people.Expression,
Expression.Quote(orderByExp)));
lambda 表达式中的参数表达式是按实例标识的,而不是像你想象的那样按名称标识。所以这里
var body = Expression.MakeBinary(ExpressionType.Equal, Person.LocalNumberType.Body, Expression.Constant(Shared.NumberType.Even));
people = people.Where(Expression.Lambda<Func<Person, bool>>(body, Expression.Parameter(typeof(Person), "p")));
正文绑定到源 Person.NumberType
表达式参数,但是您在新的 lambda 表达式中使用它,参数 不同(事件虽然相同类型和名称)。
一种可能的解决方案是重用原始参数,例如
var source = Person.LocalNumberType;
var body = Expression.Equal(source.Body, Expression.Constant(Shared.NumberType.Even));
var predicate = Expression.Lambda<Func<Person, bool>>(body, source.Parameters);
people = people.Where(predicate);