首页 > 解决方案 > 为什么“IQueryable.Where()”在此查询中提供与“IEnumerable.Where()”不同的结果?

问题描述

我正在尝试使用 linq 从 EF Core 数据集中过滤一些行,但我不明白为什么过滤 IEnumerable 与过滤 IQueryable 会给我不同的结果。

        var query = _db.Jobs
            .IsDelivered()
            .Include(a => a.JobExtras)
            .Include(a => a.Tips)
            .Include(a => a.Payments)
            .HasPayments();

        var query1 = query
            .ToList()
            .Where(a => a.Payments.Sum(b => b.Amount)
                         - a.Price.Value
                         - a.Discount
                         - a.JobExtras.Sum(c => c.Price)
                         - a.Tips.Sum(d => d.Amount)
                         > 0);

        var query2 = query
           .Where(a => a.Payments.Sum(b => b.Amount)
                         - a.Price.Value
                         - a.Discount
                         - a.JobExtras.Sum(c => c.Price)
                         - a.Tips.Sum(d => d.Amount)
                         > 0);

        Debug.WriteLine($"Record Count[Before Where Clause]: {query.Count()}");
        Debug.WriteLine($"Record Count[ToList() version]: {query1.Count()}");
        Debug.WriteLine($"Record Count[w/out ToList()]: {query2.Count()}");

这是输出:

Record Count[Before Where Clause]: 8379
Record Count[ToList() version]: 5921
Record Count[w/out ToList()]: 0

为什么 IEnumerable 版本产生 5921 条记录,而 IQueryable 版本产生 0 条记录?

标签: c#entity-frameworklinqentity-framework-core

解决方案


第一个查询使用 .NET 类型在内存中执行,而Enumerable.Sum(). 任何传入的空值都将Sum被跳过,因此您的一些数据正在通过> 0测试。

第二个查询在数据库中执行并使用 SQL 的SUM. 如果子句中表达式的任何部分Where包含 null,则该表达式将评估为 null。获取该表达式并对其进行比较 ( null > 0) 在 SQL 中始终评估为 false,因此您的所有行都被过滤了。

您的第二个查询可能是可以修复的。我没有证据证明这一点,因为我不知道您的模型(即什么可以为空),并且不确定 EF 是否可以翻译:

.Where(a => a.Payments.Where(x => x != null).Sum(b => b.Amount)
     - a.Price.Value
     - a.Discount
     - a.JobExtras.Where(x => x != null).Sum(c => c.Price)
     - a.Tips.Where(x => x != null).Sum(d => d.Amount)
     > 0);

推荐阅读