EF Core 先插入后更新条目:WebApi方法实现问题咨询
WebApi中实现「不存在则插入,后续更新」的逻辑问题
我现在在WebApi方法里需要实现这样的逻辑:如果目标元素不存在,就插入它;完成一些操作后,再对这个元素进行更新。但我现在写的代码好像有问题,现有代码如下:
Entry existingEntry = await _repo.GetEntryByIdAsync(id); existingEntry = await _repo.AddNewEntryAsync(existingAccred); // 一些操作... // 更新操作 existingAccred.IdField = myField; await _repo.UpdateEntryAsync(existingEntry);
仓储层的部分代码:
public async Task<Entry> GetEntryByIdAsync(int myId) { var result = from entry in _ctx.Set<DALENTRY>() where entry.Id == myId select entry; // 假设这里会映射成Entry实体返回 return MapToEntry(await result.FirstOrDefaultAsync()); } // AddNewEntryAsync的实现大概是这样? public async Task<Entry> AddNewEntryAsync(Entry newEntry) { var dalEntry = MapToDALEntry(newEntry); _ctx.Set<DALENTRY>().Add(dalEntry); await _ctx.SaveChangesAsync(); return MapToEntry(dalEntry); }
问题分析
你现在的代码逻辑明显有问题:
- 首先查询了
existingEntry,但直接把它替换成了新增后的Entry,这直接丢弃了查询结果,完全没做「不存在才插入」的判断 - 后续更新时用的是
existingAccred,但更新方法传的是existingEntry,变量对应关系混乱,很容易导致更新的不是同一个实体
正确的实现思路
我们需要先判断查询结果是否为null,如果是null才执行插入,否则直接使用查询到的实体;之后的操作都基于同一个实体对象,最后执行更新。
修正后的代码示例
// 1. 先查询目标元素 Entry targetEntry = await _repo.GetEntryByIdAsync(id); // 2. 如果不存在,就插入新元素 if (targetEntry == null) { // 这里注意要传入正确的新实体参数,比如基于existingAccred构造 targetEntry = await _repo.AddNewEntryAsync(existingAccred); } // 3. 执行你的若干操作... // 比如这里可以直接操作targetEntry的属性 // targetEntry.SomeField = someValue; // 4. 对同一个实体执行更新操作 // 先把需要更新的字段赋值到targetEntry上 targetEntry.IdField = myField; // 调用更新方法 await _repo.UpdateEntryAsync(targetEntry);
补充说明
- 确保仓储层的
UpdateEntryAsync方法能正确处理已跟踪的实体:如果是EF Core的话,直接修改实体属性后调用SaveChangesAsync即可,不需要额外的Update操作,除非是 detached(未被上下文跟踪)的实体 - 注意变量命名的一致性:比如
existingAccred和existingEntry尽量统一命名,避免混淆 - 如果需要保证原子性(插入和更新在同一个事务里),可以在WebApi方法里使用事务包裹整个逻辑:
using var transaction = await _ctx.Database.BeginTransactionAsync(); try { // 上面的查询、插入、更新逻辑 await _ctx.SaveChangesAsync(); await transaction.CommitAsync(); } catch (Exception) { await transaction.RollbackAsync(); throw; }
内容的提问来源于stack exchange,提问作者Irvin Dominin
相关产品推荐
相关产品推荐

