【问题标题】:Linq group by grouping wrong set of resultsLinq 通过对错误的结果集进行分组
【发布时间】:2015-11-10 19:57:01
【问题描述】:

各位开发者,

我从来没有遇到过比这个问题更接近的问题,也没有在整个互联网上找到任何答案...

我有一个简单的查询:

var data = (from b in db.vw_SpedF500
                    where b.DATABAIXA >= dtInicial && b.DATABAIXA <= dtFinal
                    where b.CODCOLIGADA == codcoligada
                    select b).ToList();

对于我正在使用的情况,视图返回的结果正好是 441 个。 我需要按名为 CSTPIS 的列对它们进行分组,该列可以具有三个不同的值(字符串):01、06 或 08。

我期望的结果计数是:

  • 01 => 170 个结果;
  • 06 => 143 个结果;
  • 08 => 128 个结果;

分组后的结果计数:

  • 01 => 170 个结果;
  • 06 => 172 个结果;
  • 08 => 109 个结果;

这是我的查询分组:

b.LinhasF500 = (from d in grupo
                                group d by d.CSTPIS into g
                                select new F500()
                                {
                                    VL_REC_CAIXA = g.Sum(f => f.VALOR.Value).ToString("F2"),

                                    CST_COFINS = g.FirstOrDefault().CSTCOFINS,
                                    VL_BC_COFINS = g.FirstOrDefault().CSTCOFINS == "08" ? null : g.Sum(f => f.VALOR.Value).ToString("F2"),
                                    ALIQ_COFINS = g.FirstOrDefault().CSTCOFINS == "08" ? null : g.FirstOrDefault().ALIQUOTACOFINS.Value.ToString("F2"),
                                    VL_COFINS = g.FirstOrDefault().CSTCOFINS == "08" ? null : g.Sum(f => f.COFINSBAIXA.Value).ToString("F2"),

                                    CST_PIS = g.FirstOrDefault().CSTPIS,
                                    ALIQ_PIS = g.FirstOrDefault().CSTPIS == "08" ? null : g.FirstOrDefault().ALIQUOTAPIS.Value.ToString("F2"),
                                    VL_PIS = g.FirstOrDefault().CSTPIS == "08" ? null : g.Sum(f => f.PISBAIXA.Value).ToString("F2"),
                                    VL_BC_PIS = g.FirstOrDefault().CSTPIS == "08" ? null : g.Sum(f => f.VALOR.Value).ToString("F2")
                                }).ToList();

为什么 Linq 会重复 10 个结果?

PS: Group by 直接在 sql 查询上工作正常

编辑

查看伊万的评论后,我注意到以下内容:

EF 使用三列为我的视图确定了一个复合键:IDLAN、CODCFO 和 CODCOLIGADA。

运行此查询后

select IDLAN, CODCFO, CODCOLIGADA, COUNT(IDLAN), COUNT(CODCFO), COUNT(CODCOLIGADA) from vw_SpedF500
where 0=0
    AND DATABAIXA BETWEEN '2015-08-01' AND '2015-08-31'
    and CODCOLIGADA = 7
GROUP BY IDLAN, CODCFO, CODCOLIGADA
HAVING COUNT(IDLAN) > 1 AND COUNT(CODCFO) > 1 AND COUNT(CODCOLIGADA) > 1
ORDER BY IDLAN

我得到 124 行,其中所有三个键都有多个寄存器。

有什么方法可以在 EF 上完成这项工作吗?

编辑

我再次重新检查了所有内容。第一个查询返回正确的结果并且对象已经在内存中。

问题发生在对已经在内存中的对象进行分组时,而不是在查询期间。与EF无关。

我想我会将其更改为 SqlCommand(会导致一个小的性能问题,因为我必须运行此查询 3 次,但是...)

【问题讨论】:

  • vw_SpedF500 是数据库还是视图?如果它是一个视图(如其名称所示),请查看 stackoverflow.com/questions/33583309/… - Gert Arnold 的回答
  • 建议的简化:不要使用g.FirstOrDefault().CSTPIS,而是使用g.Key,因为这是关键,并且对于组中的每条记录都应该相同,并且成本略低。
  • 后一个查询使用grupo 作为其起点,而不是第一个查询创建的data。也许从数据开始的地方开始,grupo 发生了一些变化?
  • @KaseySpeakman 第二个查询只是封装在一个方法中。 Grupo 与数据完全一样(我已经检查了三次)。我喜欢你关于使用组密钥的提示。没想到。
  • @IvanStoev 在运行了一些测试之后,我注意到我确实遇到了 Gert Arnold 的回答中提到的问题。将更新问题。

标签: c# sql-server entity-framework linq entity-framework-6


【解决方案1】:

看起来您的 LINQ 查询可能过于严格 - 这让我有好几次感到困惑。通过删除您的第二个 where 关键字并将最后的语句与您的第一个语句组合来使用限制较少的过滤器。

这样的东西应该会给你你想要的:

var data = (from b in db.vw_SpedF500
            where b.DATABAIXA >= dtInicial &&
                  b.DATABAIXA <= dtFinal &&
                  b.CODCOLIGADA == codcoligada
            select b).ToList();

如果您试图确保您的 LINQ 查询仅返回与此匹配的结果:

b.DATABAIXA >= dtInicial && b.DATABAIXA <= dtFinal

OR 这个(相对于 and 这个)

b.CODCOLIGADA == codcoligada

你可以试试这个:

var data = (from b in db.vw_SpedF500
            where (b.DATABAIXA >= dtInicial &&
                   b.DATABAIXA <= dtFinal) ||
                   b.CODCOLIGADA == codcoligada
            select b).ToList();

希望我理解正确!

【讨论】:

  • 第一个查询工作正常,正如我所说的。使用多个 where 子句与对 linq to 实体使用多个 && 相同,因为它返回相同的 sql 查询。我的问题与查询后的结果分组有关。 =)
猜你喜欢
  • 2023-02-08
  • 1970-01-01
  • 2023-03-23
  • 2010-10-01
  • 1970-01-01
  • 2017-04-12
  • 1970-01-01
  • 1970-01-01
  • 2019-08-06
相关资源
最近更新 更多