如何在LINQ查询的Select语句中更新对象绑定字典的各值
解决方案
首先,你当前的代码存在两个核心问题:
- 所有
SummaryData实例会共享同一个SD.serviceQuantityPair字典(引用类型特性),修改一个会影响所有实例; - 没有对字典的每个键执行对应的计数逻辑。
下面提供两种可行的实现方式,兼顾简洁性和性能:
方式一:直接在字典初始化时完成计数(简洁版)
在Select语句中,为每个分组创建独立的字典实例,同时通过Count方法直接计算每个键对应的记录数:
sumdata = await _dbContext.CovidServiceRequests.AsNoTracking() .Where(wh => wh.CreatedTimestamp >= dFromDate && wh.CreatedTimestamp <= dToDate) .GroupBy(gb => gb.CreatedTimestamp!.Value.Date) .Select(s => new SummaryData() { requestDate = s.Key.ToString(groupByDate), // 为每个SummaryData创建新字典,避免引用共享 serviceQuantityPair = SD.serviceQuantityPair.ToDictionary( kv => kv.Key, kv => s.Count(item => item.RequestedCode == kv.Key) ), qty = s.Count(wh => wh.RequestedCode == "A") // 保留原有的单独计数 }) .ToListAsync();
方式二:预统计所有代码计数(高性能版)
如果分组数据量较大,多次调用Count会重复遍历分组数据,性能较低。可以先在分组内预统计所有RequestedCode的数量,再映射到目标字典:
sumdata = await _dbContext.CovidServiceRequests.AsNoTracking() .Where(wh => wh.CreatedTimestamp >= dFromDate && wh.CreatedTimestamp <= dToDate) .GroupBy(gb => gb.CreatedTimestamp!.Value.Date) .Select(s => { // 先统计当前分组内所有RequestedCode的出现次数 var codeCountMap = s.GroupBy(item => item.RequestedCode) .ToDictionary(g => g.Key, g => g.Count()); return new SummaryData() { requestDate = s.Key.ToString(groupByDate), serviceQuantityPair = SD.serviceQuantityPair.ToDictionary( kv => kv.Key, kv => codeCountMap.TryGetValue(kv.Key, out var count) ? count : 0 ), qty = codeCountMap.TryGetValue("A", out var aCount) ? aCount : 0 }; }) .ToListAsync();
关键说明
- 避免引用共享:必须通过
ToDictionary创建新的字典实例,不能直接复用SD.serviceQuantityPair,否则所有SummaryData会共用同一个字典,修改时互相影响。 - 动态键适配:如果后续字典的键是动态生成的(比如从配置或数据库读取),只需确保
SD.serviceQuantityPair包含所有需要统计的键,上述代码会自动为每个键匹配对应的计数,不存在的键则保持0。 - 异步处理:原代码缺少
ToListAsync(),LINQ查询在调用异步执行方法前不会实际执行,需要添加此方法触发数据库查询。
内容的提问来源于stack exchange,提问作者Sanjay Kukreja
相关产品推荐
相关产品推荐

