如何使用LINQ实现单表全列+另一表指定列的左连接聚合查询
将SQL转换为LINQ实现
原SQL语句
SELECT p.Id, p.Item, h.Date,h.Shop, SUM(h.Harvested) AS Harvested FROM Plantings p LEFT JOIN Harvests h ON p.Id = h.Id GROUP By p.Id, p.Item, h.Date, h.Shop
这段SQL通过左连接关联Plantings和Harvests表,按Plantings.Id、Plantings.Item、Harvests.Date、Harvests.Shop分组,计算每组的Harvested总和。
表结构
Plantings表
| Id | Item | Planted |
|---|---|---|
| 3 | Carrot | 2.00 |
| 4 | Apple | 1.00 |
Harvests表
| HId | Item | Harvested | Id | Date | Shop |
|---|---|---|---|---|---|
| 1 | Carrot | 10.00 | 3 | 4/09/2024 | 4 |
| 2 | Apple | 20.00 | 4 | 9/09/2024 | 11 |
| 3 | Carrot | 5.00 | 3 | 4/09/2024 | 4 |
| 4 | Carrot | 3 | 7/09/2024 | 2 |
尝试的代码(存在问题)
IEnumerable DataSource = (from p in _context.Plantings join h in _context.Harvests on p.Id equals h.Id select t1).ToList();
这段代码的问题:
- 使用内连接而非左连接,会丢失
Plantings中无对应Harvests记录的数据 - 缺少分组和求和逻辑,无法实现原SQL的统计功能
select t1中t1未定义,编译报错
预期输出
| Id | Item | Harvested |
|---|---|---|
| 3 | Carrot | 15.00 |
| 4 | Apple | 20.00 |
| 3 | Carrot |
正确的LINQ实现
查询语法版本
var dataSource = (from p in _context.Plantings // 左连接:保留所有Plantings记录,即使无对应Harvests数据 join h in _context.Harvests on p.Id equals h.Id into harvestGroup from h in harvestGroup.DefaultIfEmpty() // 按原SQL指定维度分组 group h by new { p.Id, p.Item, h.Date, h.Shop } into grouped select new { grouped.Key.Id, grouped.Key.Item, grouped.Key.Date, grouped.Key.Shop, // 计算Harvested总和,自动忽略null值 Harvested = grouped.Sum(x => x.Harvested) }).ToList();
方法语法版本
var dataSource = _context.Plantings // 左连接关联两个表 .GroupJoin( _context.Harvests, planting => planting.Id, harvest => harvest.Id, (planting, harvests) => new { Planting = planting, Harvests = harvests } ) // 展开分组,处理无对应Harvests的情况 .SelectMany( x => x.Harvests.DefaultIfEmpty(), (x, harvest) => new { x.Planting.Id, x.Planting.Item, harvest.Date, harvest.Shop, harvest.Harvested } ) // 按指定维度分组 .GroupBy(item => new { item.Id, item.Item, item.Date, item.Shop }) // 投影最终结果 .Select(grouped => new { grouped.Key.Id, grouped.Key.Item, grouped.Key.Date, grouped.Key.Shop, Harvested = grouped.Sum(item => item.Harvested) }) .ToList();
如果只需要输出预期的Id、Item、Harvested三列,只需调整select部分,去掉Date和Shop字段即可。
内容的提问来源于stack exchange,提问作者Milie24
相关产品推荐
相关产品推荐

