【问题标题】:Return multiple aggregate columns in LINQ在 LINQ 中返回多个聚合列
【发布时间】:2020-02-01 13:42:55
【问题描述】:

我想将以下 SQL 翻译成 LINQ:

SELECT
    (Select count(BidID)) as TotalBidNum,
    (Select sum(Amount)) as TotalBidVal
FROM Bids

我试过了:

from b in _dataContext.Bids
select new { TotalBidVal = b.Sum(p => p.Amount), TotalBidNum = b.Count(p => p.BidId) }

但出现错误“Bids 不包含“Sum”的定义,并且找不到接受“Bids”类型的第一个参数的扩展方法“Sum”。

如何在 LINQ 中做到这一点?

谢谢

结论:

最后的答案是:

var ctx = _dataContext.Bids;

var itemsBid = (from b in _dataContext.Bids
               select new { TotalBidVal = ctx.Sum(p => p.Amount), TotalBidNum = ctx.Count() }).First();

【问题讨论】:

    标签: linq-to-sql aggregate


    【解决方案1】:

    您可以使用GroupBy 编写此查询。 Lambda表达式如下:

        var itemsBid = db.Bids
                         .GroupBy( i => 1)
                         .Select( g => new
                         {
                              TotalBidVal = g.Sum(item => item.Amount), 
                              TotalBidNum = g.Count(item => item.BidId)
                         });
    

    【讨论】:

    • 正是我需要的(虽然在普通的旧 linq 中,没有 linq2SQL 或 EF)。
    • 这很简单,但可以解决问题。顺便说一下,我想知道运算符“.GroupBy(i => 1)”的用途。为什么我们需要它?
    • 我们如何知道聚合函数(SumCount)是在一次迭代中计算出来的?难道不能为此对组进行两次迭代吗? (这是我想避免的)
    • @Thomas.Benz 该表达式通过一个常量对可迭代对象进行分组,因此可迭代对象的所有元素最终都在一个组中。通常使用 GroupBy 你提供一个函数,以便将项目放入多个不同的组中
    • @Miguel 感谢您的有用解释。
    【解决方案2】:

    你可以试试这个。变量 b 是一个实体(对于每次迭代),而 ctx 是一个实体集,它具有您需要的扩展方法。

    var ctx = _dataContext.Bids;
    
    var result = ctx
        .Select( x => new
        {
            TotalBidVal = ctx.Sum  ( p => p.Amount ),
            TotalBidNum = ctx.Count( p => p.BidId  )
        } )
        .First();
    

    【讨论】:

    • 这确实解决了错误(尽管这似乎是一个不必要的步骤 - 为什么需要它?)。我的 Count(p=> p.BidID) 有问题 - p.BidID 不是布尔值的错误。我用 Count() 替换了它,现在查询返回正确的总和和计数,但不是单行。一遍又一遍地重复同一行 - 我假设 Bids 表中的行数一样多。如何像原始 SQL 查询一样返回单行?
    • @BKahuna 您的查询说“来自 _dataContext.Bids 中的 b”,这是一个迭代。即使您尝试仅计算总和和计数,您也不会得到一个结果。您可以通过调用 First() 来结束 lambda 表达式。这只会像我一样给你一个结果。
    • @BKahuna 请将我的答案滚动到最后,看看我打的最后一个电话。我调用 First() 方法,这将确保我只返回一行(生成的 sql 是 Top(1) )
    • 当我这样做时,我得到一个非常低效的CROSS JOIN SQL 查询。我需要使用GroupBy( x => 1 ) 技巧来获得有效的查询。
    【解决方案3】:

    这是 Scartag 解决方案的替代方案:

    (from b in _dataContext.Bids.Take(1)
    select new 
    {
        TotalBidVal = _dataContext.Bids.Sum(p => p.Amount), 
        TotalBidNum = _dataContext.Bids.Count()
    }).Single();
    

    虽然没有真正的理由你不能说:

    var result = new 
    {
        TotalBidVal = _dataContext.Bids.Sum(p => p.Amount), 
        TotalBidNum = _dataContext.Bids.Count()
    };
    

    两次访问数据库,但可读性很强

    【讨论】:

      【解决方案4】:

      您可以使用Aggregate Clause 来做到这一点。

      Aggregate t In _dataContext.Bids
      Into TotalBidNum = Count(BidID),
           TotalBidVal = Sum(Amount)
      

      如果您使用 Fx4+ 或 Fx2 的扩展 dll,您还可以通过使用来受益于并行性

      Aggregate t In _dataContext.Bids.AsParallel
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-15
        • 2011-04-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-22
        • 2019-06-06
        • 2013-03-15
        相关资源
        最近更新 更多