【问题标题】:Linq group by multiple fields across different tablesLinq 按跨不同表的多个字段分组
【发布时间】:2012-07-18 07:57:34
【问题描述】:

在尝试将此 SQL 查询转换为 LINQ 时,我遇到了 group by 问题。 如何按源自多个表的多个列进行分组? 下面的 linq 查询根本无法编译,所以我需要正确的语法

原始 SQL 查询

select LTRIM(RTRIM(e.Shortname)) 
Name, LTRIM(RTRIM(j.JobName)) 
JobName, j.JobCode, 
SUM(Hours) Hours, 
MAX(ce.LatestTimesheetEntry) LastTimeSubmitted 
from TWCTL.TW.Postings p
join TWCTL.TW.Employees e on e.EmployeeId = p.EmployeeId
join TWCTL.TW.Jobs j on j.JobCode = p.JobCode
join CentralTimeEmployees.dbo.Employees ce on ce.CtEmployeeId = e.EmployeeId
where (e.CostCentreId = 1 or e.CostCentreId = 3) 
and (p.TransactionDate >= '2012-01-01' and p.TransactionDate <= '2012-07-01') 
and j.JobCode <> 'CTCIT00001' 
and ce.DatabaseCode = 'CTL' 
and (ce.CostCentreId = 1 or ce.CostCentreId = 3)
group by j.JobName, j.JobCode, Shortname
order by e.Shortname, j.JobName

Linq 查询尝试(不工作)

var model = 
        from p in context.Postings
        join e in context.Employees on p.EmployeeId equals e.EmployeeId
        join j in context.Jobs on p.JobCode equals j.JobCode
        join ce in context.CentralTimeEmployees on e.EmployeeId equals ce.CtEmployeeId
        where (e.CostCentreId == 5 || e.CostCentreId == 3)
                && (p.TransactionDate >= fromDate
                    && p.TransactionDate <= toDate)
                && j.JobCode != "CTCIT00001"
                && ce.DatabaseCode == "CTL"
                && (ce.CostCentreId == 1 || ce.CostCentreId == 3)
        group j by new {j.JobName, j.JobCode} into g1
        group e by e.Shortname into g2    <- doesnt work??        
        select
            new ProjectHoursViewModel
                {Posting = p, Job = g1.Key.JobName, Employee = e, CentralTimeEmployee = ce};

【问题讨论】:

  • 因为出现错误而无法正常工作...?得到错误的结果...?什么?
  • @JeffMercado 我已经更新了帖子,基本上语法不正确并且无法编译,我需要按区域分组的一些帮助。塔
  • @PaulStoker:编译器是否给你一个拒绝编译它的理由?我认为虽然它与多个 group bys 有关,但我只对 linq 使用方法语法,所以我不确定问题到底出在哪里。

标签: c# linq


【解决方案1】:

对于初学者,您的查询是不等价的。次要的事情真的很喜欢检查不同的值,但主要的一点是您没有按相同的键进行分组。您在查询中遗漏的按 JobCode 分组的 SQL。你试图分组太多而不是订购它。您要聚合的值应该是您要分组的值。

至于为什么会出现语法错误,在进行延续后(在group byselect 子句中使用into),前一个作用域中的所有变量都将丢失,只有延续变量仍然存在(在您的情况下为g1)。您尝试引用 e,现在超出了您的问题范围。

我认为查询应该更像这样:

var fromDate = new DateTime(2012, 1, 1);
var toDate = new DateTime(2012, 7, 1);
var query = 
    from p in dc.Postings
    join e in dc.Employees on p.EmployeeId equals e.EmployeeId
    join j in dc.Jobs on p.JobCode equals j.JobCode
    join ce in dc.CentralTimeEmployees on e.EmployeeId equals ce.CtEmployeeId
    where (e.CostCentreId == 1 || e.CostCentreId == 3) // the SQL tested 1 or 3
       && (p.TransactionDate >= fromDate && p.TransactionDate <= toDate)
       && j.JobCode != "CTCIT00001"
       && ce.DatabaseCode == "CTL"
       && (ce.CostCentreId == 1 || ce.CostCentreId == 3)
    group new { ce.Hours, ce.LatestTimesheetEntry }
       by new { j.JobName, j.JobCode, e.ShortName } into g
    orderby g.Key.ShortName, g.Key.JobName
    select new
    {
        Name = g.Key.ShortName.Trim(),
        JobName = g.Key.JobName.Trim(),
        JobCode = g.Key.JobCode,
        Hours = g.Sum(x => x.Hours),
        LastTimeSubmitted = g.Max(x => x.LatestTimesheetEntry),
    };

【讨论】:

  • 谢谢杰夫,这几乎成功了,我几乎在两个单独的查询中都有它,但我真的不想这样做;-)
  • 在上面的查询中,我们如何使用 count() 函数。我试过g.Count(x =&gt; x.JobCode),但它抛出了一个错误-Cannot implicitly convert type ******** to bool。还有其他的做count操作吗?
  • @RohitSawai:通过将 lambda 传递给 Count() 函数,它是选择要计数的项目的谓词。它应该返回一个布尔值,很像 Where()First()Single() 等函数。
  • @JeffMercado 感谢您的解释,让我思考并解决了我的问题。我盲目地镜像上面的代码以使 count() 函数工作。您的解释指导了我,如何实现我想要的。
猜你喜欢
  • 2016-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-20
  • 2014-01-02
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多