【问题标题】:The LINQ expression 'DbSet<Person>() .Where(p => p.Id % 2 == 0 ? Even : Odd == Even)' could not be translated无法翻译 LINQ 表达式 'DbSet<Person>() .Where(p => p.Id % 2 == 0 ? Even : Odd == Even)'
【发布时间】:2022-01-05 05:03:43
【问题描述】:

我有一个班级人员,其中有一些汇总值,例如如果 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 ? 偶数:奇数 == 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)));

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      猜你喜欢
      • 2020-09-29
      • 2012-08-20
      • 2013-08-07
      • 1970-01-01
      • 2018-12-04
      • 1970-01-01
      • 2022-01-19
      • 2021-12-28
      • 1970-01-01
      相关资源
      最近更新 更多