如何用LINQ实现主表扣除多日志表累计工时的计算
LINQ查询修正方案:计算用户剩余工时
原代码存在的问题
- 提前调用
ToList()会把两张表的全量数据加载到内存,浪费数据库的聚合计算能力,性能低下 - 直接关联两张表会返回多条结果(每条日志对应一条),没有对用户的完成工时做累加计算,不符合需求
- 试图用
GoalHours实体接收结果,但该实体没有Completed和Remaining属性,编译直接报错 - 没有过滤日志表的用户范围,会关联到其他用户的工时记录
修正后的LINQ代码
方案1:查询表达式写法
var userId = 4; var result = from gh in db.GoalHours where gh.UserID == userId join ah in db.AccumulatedHours on gh.ID equals ah.GH_ID into ahGroup select new { ID = gh.ID, User = gh.User, // 假设GoalHours有User字段 Target = gh.Target, Completed = ahGroup.Sum(x => x.Completed) ?? 0, // 累加完成工时,无日志时返回0 Remaining = gh.Target - (ahGroup.Sum(x => x.Completed) ?? 0) }; // 获取单个用户的结果 var userRemainingHours = result.FirstOrDefault();
方案2:方法链写法(更简洁)
var userId = 4; var userRemainingHours = db.GoalHours .Where(gh => gh.UserID == userId) .GroupJoin( db.AccumulatedHours, gh => gh.ID, ah => ah.GH_ID, (gh, ahGroup) => new { ID = gh.ID, User = gh.User, Target = gh.Target, Completed = ahGroup.Sum(x => x.Completed) ?? 0, Remaining = gh.Target - (ahGroup.Sum(x => x.Completed) ?? 0) }) .FirstOrDefault();
关键说明
- 使用
GroupJoin而非普通Join,可以将当前目标的所有日志记录分组,方便做累加计算 - 用
Sum(x => x.Completed)统计累计完成工时,加上?? 0处理用户无日志记录的情况(避免null值报错) - 不提前调用
ToList(),让LINQ to SQL将查询转换为SQL语句在数据库执行,性能更优 - 使用匿名类(或自定义DTO)接收结果,避免修改原实体类结构
内容的提问来源于stack exchange,提问作者Manny Sanchez
相关产品推荐
相关产品推荐

