将JSON字符串转为列表并对比数据库列表,仅新增差异记录的实现问题
问题分析与修正方案
你的需求是仅向数据库添加新列表中存在但数据库不存在的角色权限动作记录,当前代码存在几个核心问题:
- 虽然计算了
items.Except(list)的差异结果,但完全未使用,反而循环所有items执行插入,会导致重复添加数据库已有的记录 SaveChanges()放在循环内部,每插入一条就提交一次,数据库交互次数过多,效率极低Except默认使用引用相等性对比,而AccessActionViewModel和RoleAccessAction是不同类型,直接对比无法得到正确的差异数据
修正后的代码
[HttpPost] public async Task<IActionResult> AddRoleAccessActions(string SelectedItems, string RoleName) { // 反序列化得到选中的权限动作列表 List<AccessActionViewModel> items = JsonConvert.DeserializeObject<List<AccessActionViewModel>>(SelectedItems); if (!items.Any()) { return Ok(new ReturnModel(new Collection { MessageLib.Message.Create.Successful }, new List<string>(), MessageLib.Message.statusCode.CreateSuccessful)); } // 获取该角色已存在的权限动作名称集合,用HashSet提升查询效率 var existingActionNames = await _context.RoleAccessAction .Where(a => a.RoleName == RoleName) .Select(a => a.AccessActionName) .ToHashSetAsync(); // 筛选出需要新增的项:不在已有集合中的动作 var actionsToAdd = items .Where(item => !existingActionNames.Contains(item.AccessActionName)) .Select(item => new RoleAccessAction { RoleName = RoleName, AccessActionName = item.AccessActionName }) .ToList(); // 如果有需要新增的记录,批量添加并一次性保存 if (actionsToAdd.Any()) { await _context.RoleAccessAction.AddRangeAsync(actionsToAdd); await _context.SaveChangesAsync(); } return Ok(new ReturnModel(new Collection { MessageLib.Message.Create.Successful }, new List<string>(), MessageLib.Message.statusCode.CreateSuccessful)); }
关键优化点
- 高效对比:通过
Select只提取数据库中已有的动作名称,存入HashSet将查询时间复杂度从O(n)降到O(1),大幅提升对比效率 - 批量操作:使用
AddRangeAsync批量添加实体,SaveChangesAsync仅调用一次,减少数据库交互次数 - 精准筛选:直接通过
AccessActionName属性对比,确保只新增数据库不存在的记录 - 空值处理:提前判断
items是否为空,避免无效的数据库查询和循环操作
内容的提问来源于stack exchange,提问作者sadegh
相关产品推荐
相关产品推荐

