代码之家  ›  专栏  ›  技术社区  ›  Martin

LINQ:在WHERE子句中应用过滤器,但需要检查SUM(子查询)的值-在内部解释

  •  0
  • Martin  · 技术社区  · 15 年前

    我有下面的LINQ及其工作很好,但我需要能够检查一个变量,并且根据值只显示记录的一个子集。我会解释的……

    这里是SQL

    var test = from c in db.C
     select new {
      Period = c.M.Period,
      Group = c.Code,
      Code = c.ClientCode,
      Name = c.ClientName,
      Amount = (System.Int32)
       ((from m0 in db.M
         where
          m0.ClientCode == c.ClientCode
           group m0 by new {
            m0.ClientCode
             } into g
              select new {
               Expr1 = (System.Int32)g.Sum(p => p.Amount)
        }).First().Expr1)
     }
    

    返回6条记录,每条记录的金额如下

    一百 二百 三百 四百 五百 六百

    我需要动态地加上where并检查一个名为filter的变量(在c_中),如果filter=1,则返回所有记录<300;如果filter=2,则返回所有记录>=300;如果变量为空,则不应用任何筛选器并返回所有记录。

    现在我感到困惑的是,这个数量不在数据库中,它实际上是子查询。

    有人能帮忙吗?

    3 回复  |  直到 15 年前
        1
  •  3
  •   Jon Skeet    15 年前

    我认为如果您从简化查询开始,这会有所帮助。您使用匿名类型没有任何特殊的原因(如果只有一个属性,为什么要麻烦?)并按已筛选的值分组。换句话说,您的查询等价于:

    var test = from c in db.C
     select new {
      Period = c.M.Period,
      Group = c.Code,
      Code = c.ClientCode,
      Name = c.ClientName,
      Amount = db.M
                 .Where(m0 => m0.ClientCode == c.ClientCode)
                 .Sum(m0 => m0.Amount)
    };
    

    使用一个更简单的查询可能会更容易地修复其余的问题。它可能简单如下:

    var filtered = filter == 1 ? test.Where(t => t.Amount < 300)
                 : filter == 2 ? test.Where(t => t.Amount >= 300)
                 : test;
    
        2
  •  1
  •   Dean Chalk    15 年前

    试试这个

    var test = from c in db.C
    select new {
    
        Period = c.M.Period,
        Group = c.Code,
        Code = c.ClientCode,
        Name = c.ClientName,
        Amount = (System.Int32)
            ((from m0 in db.M
                where
                m0.ClientCode == c.ClientCode
                group m0 by new {
                m0.ClientCode
                    } into g
                    select new {
                    Expr1 = (System.Int32)g.Sum(p => p.Amount)
                    }).First().Expr1).Where(i => 
                        {
                            if (filter == 1) 
                                i.Expr1 < 300; 
                                else if (filter == 2) 
                                i.Expr1 >= 300; 
                        })
    
        3
  •  1
  •   VVS    15 年前

    基本上,我接受了乔恩的回答,并将过滤器集成到查询中:

    int filter = 1;
    
    Func<int, bool> isRelevant = (amount)=>{
        switch(filter)
        {
            case 1: return amount < 300;
            case 2: return amount > 300;
            default: throw new ArgumentException();
        }
    };
    
    var test = from c in db.C
                let amount = db.M
                                .Where(m0 => m0.ClientCode == c.ClientCode)
                                .Sum(m0 => m0.Amount)
                where isRelevant(amount)
                select new
                {
                    Period = c.M.Period,
                    Group = c.Code,
                    Code = c.ClientCode,
                    Name = c.ClientName,
                    Amount = amount
                };