如何将含Group By、Having子句的SQL转换为C# EF6的LINQ语句
实现代码
推荐优先使用提前过滤的写法,性能更优:
// 替换为你的实际入参 int targetRegisteredCustomerId = 目标客户ID; int targetSiteId = 目标站点ID; var queryResult = context.WholesaleCredit // 提前过滤不符合条件的数据,减少后续分组计算的数据量 .Where(x => x.ExpirationUTCDateTime > DateTime.Now && x.RegisteredCustomerId == targetRegisteredCustomerId && x.Site.Id == targetSiteId) // 按照两个字段分组,对应SQL的GROUP BY逻辑 .GroupBy(x => new { x.RegisteredCustomerId, SiteId = x.Site.Id }) // 执行聚合计算,对应SQL的sum、max逻辑 .Select(g => new { TotalSiteCreditAmount = g.Sum(x => x.RemainingAmount), MaxExpiryDate = g.Max(x => x.ExpirationUTCDateTime) }) // 符合条件的分组最多只有1条,取第一条结果即可 .FirstOrDefault();
说明
- 你之前的代码只按
RegisteredCustomerId单个字段分组,和原始SQL的双字段分组逻辑不符,需要改为匿名类包含两个分组键即可。 - 原始SQL的
HAVING过滤条件是分组键的等值匹配,提前放到WHERE中过滤,执行效率远高于分组后再过滤,最终生成的SQL执行结果完全一致。 - 如果你需要严格对齐原始SQL的
HAVING写法,可以使用下面的版本:
int targetRegisteredCustomerId = 目标客户ID; int targetSiteId = 目标站点ID; var queryResult = context.WholesaleCredit .Where(x => x.ExpirationUTCDateTime > DateTime.Now) .GroupBy(x => new { x.RegisteredCustomerId, SiteId = x.Site.Id }) // 对应原始SQL的HAVING过滤逻辑 .Where(g => g.Key.RegisteredCustomerId == targetRegisteredCustomerId && g.Key.SiteId == targetSiteId) .Select(g => new { TotalSiteCreditAmount = g.Sum(x => x.RemainingAmount), MaxExpiryDate = g.Max(x => x.ExpirationUTCDateTime) }) .FirstOrDefault();
- 如果你的
WholesaleCredits实体类后续补充了显式的SiteId字段,直接替换x.Site.Id为x.SiteId即可,查询性能会更高。 - 若没有符合条件的数据,
queryResult会返回null,使用前建议做空值判断。
内容的提问来源于stack exchange,提问作者QA_A
相关产品推荐
相关产品推荐

