【问题标题】:Counting while mapping to an object in a linq subquery映射到 linq 子查询中的对象时计数
【发布时间】:2019-06-15 16:42:29
【问题描述】:

我有一个使用 let 语句的 Linq 查询,我从中派生了几个子查询。目前,我正在做 3 个子查询来使用 3 个相同的连接来派生计数,我希望将它们组合成一个只有一个连接的子查询。我有这样的事情:

let TheFruits = (complex query).ToList(),

Counter1 = (from TheTable in MyDC.SomeTable

             join x in Thefruits on                                                                   
             TheTable.FruitID equals x.FruitID

             where x.Field1 == 1

             select x).Count(),

Counter2 = (from TheTable in MyDC.SomeTable

             join x in Thefruits on                                                                   
             TheTable.FruitID equals x.FruitID

             where x.Field2 == 2

             select x).Count(),

Counter3 = (from TheTable in MyDC.SomeTable

             join x in Thefruits on                                                                   
             TheTable.FruitID equals x.FruitID

             where x.Field3 == 3

             select x).Count(),

为了替换 3 个连接,我想写这样的东西,但我没有在对象属性中获取扩展方法:

let TheFruits = (complex query).ToList(),

TheCounterObject = (from TheTable in MyDC.SomeTable

                    join x in Thefruits on                                                                   
                    TheTable.FruitID equals x.FruitID

                    select new CounterObject()
                    {
                        Count1 = x.Where....Count(),
                        Count2 = x.Where....Count(),
                        Count3 = x.Where....Count(),

                        //not getting .Where extension

                    }).Single()

问题是我没有得到扩展方法,只有表格列。在我提供的简单示例中,.Where 子句仅匹配一个条件,但在我的实际子查询中,涉及 DateTimes 和其他条件。

如何在对象映射阶段运行计数?

编辑

经过更多的努力,我现在有了以下内容:

let TheFruits = (complex query).ToList(),

TheCounterObject = (from TheTable in MyDC.SomeTable

                    join x in TheFruits on                                                                   
                    TheTable.FruitID equals x.FruitID

                    into TheSubFruits

                    select new CounterObject()
                    {
                        Count1 = TheSubFruits.Where(x.FruitID == TheTable.FruitID && other conditions).Count(),

                        Count2 = TheSubFruits.Where(x.FruitID == TheTable.FruitID && other conditions).Count(),

                        Count3 = TheSubFruits.Where(x.FruitID == TheTable.FruitID && other conditions).Count()
                    }).First()

问题是计数错误,如果我使用 .Single() 而不是 .First() 我还会收到“序列包含多个元素”错误。

为什么这个子查询返回的计数不与 3 个子查询相同?我需要改变什么?

【问题讨论】:

  • TheTable.FruitID 等于 x.FruitID 其中 x.Field2 == 1 || x.Field2 == 2 || x.Field2 == 3
  • 我想他还是想单独数水果。
  • 您可以按 FruitID 分组,然后计算每个分组的数量。
  • @jdweng:实际的谓词比较复杂,按一个条件分组的方法是行不通的。

标签: c# linq linq-to-sql


【解决方案1】:

您没有在 x 上获得 .Where 扩展名,因为此时 x 不再是可枚举的。 x 代表每个单独的水果,但您想将.Where 应用于所有水果。为此,您可以进行联接,然后执行我在编辑中显示的计数。

编辑

如果您需要针对不同条件进行单独计数,我建议您这样做:

var joined = (from TheTable in MyDC.SomeTable
              join x in Thefruits on                                   
              TheTable.FruitID equals x.FruitID
              select x).ToList();

var count1 = joined.Where(...).Count();
var count2 = joined.Where(...).Count();
var count3 = joined.Where(...).Count();

这将允许您拥有多个条件,如果您需要,这些条件甚至可以重叠并计算相同的对象。它与您最初拥有的非常相似,但它只执行一次连接。

编辑#2

再想一想之后,您可以做一些与您在第二个示例中展示的内容非常相似的事情,并将其与聚合相结合,可能会得到您正在寻找的结果。

var counts = (from TheTable in MyDC.SomeTable
              join x in Thefruits on                                   
              TheTable.FruitID equals x.FruitID
              select new {
                  // Calculate whether this object be included in each count 
                  Count1 = x.FruitId == 1 ? 1 : 0,
                  Count2 = x.FruitId == 2 ? 1 : 0,
                  Count3 = x.FruitId == 3 ? 1 : 0
              }).Aggregate((acc, i) => new {
                  Count1 = acc.Count1 + i.Count1,
                  Count2 = acc.Count2 + i.Count2,
                  Count3 = acc.Count3 + i.Count3
              });

这是一个正在工作的example,它带有假数据类,现在带有一个连接。这可能最接近您要查找的内容,因为它只执行一次连接,将对象计为执行映射,并允许多种复杂条件。

【讨论】:

  • 就像我在问题中解释的那样,子查询的 .Where 子句具有更复杂的谓词,无法分组
  • 您可以在 groupby 中使用更复杂的条件。这样做会使Key 不是很有用,但我已经更新了我的假示例,只对大于 10 岁的年龄进行分组。
  • 这实际上取决于您尝试将组划分为什么,以及相同的条件是否适用于所有不同的计数。如果您需要针对不同的条件进行单独的计数,这将不起作用。
  • 我对问题进行了编辑,添加了一些我测试过的内容。
  • 你试过我最新的解决方案了吗?我现在在我的演示中添加了一个连接,以更接近您想要实现的目标。让我担心您的新解决方案的事情是您仍在运行.Where 3 次,我认为您在映射阶段试图摆脱它。运行 .Where...Count() 3 次意味着您仍在枚举整个加入的子列表 3 次。我的新解决方案只对您想要的计数进行一次枚举。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 2014-02-11
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多