我这里有一个控制器,该控制器具有创建组的动作-它写入两个不同的数据库表。如下所示,我正在检查该组是否存在,因此只能有一个具有唯一名称的组,但是如果两个请求同时输入相同的组名,我会看到此代码是错误的,但是我觉得这几率极低。
这是我的代码,然后我遇到三个问题:
[HttpPost]
public async Task<ActionResult> Post(CreateGroupDto createGroupDto)
{
//See if this group exists yet (todo: move to action filter)
var existingGroup = _dbContext.Groups.SingleOrDefaultAsync(g => g.Name.ToLower() == createGroupDto.Name.ToLower());
//The group name isn't taken yet, so create this group
if (existingGroup == null)
{
var user = await _dbContext.Users.FindAsync(GetClaimsUserId());
var group = _mapper.Map<CreateGroupDto, Group>(createGroupDto);
//Add the Group LINE A
await _dbContext.Groups.AddAsync(group);
//Add the user as admin of this group LINE B
await _dbContext.UserGroups.AddAsync(new UserGroup { .. values set here ..} );
//Now that everything is added, save changes
//LINE C
await _dbContext.SaveChangesAsync();
return Created("/api/groups/", group.Id);
}
else
return BadRequest();
}
虽然这段代码对我来说很好用,但如果出现问题并希望仅解决以下问题,我想避免调用SaveChangesAsync():
问题#1 如果运行A行,则在MEMORY dbContext中添加一个新组
如果B行运行,则在MEMORY dbContext中添加一个新的UserGroup
运行C行时,它将两者都保存到数据库中,并且如果其中任何一个发生异常,那么ENTIRE事务都会回滚(部分状态什么都没有保留),并且API的调用者返回500错误。好像没有任何数据保存。
第2个问题 设置完所有内容后,可以立即调用SaveChanges吗?我可以看到它是如何上下文的-有时我想保存一下以查看是否在添加其他时间之前起作用,有时我想保存以同时添加所有内容。许多人说DbContext是一个UOW,因此在这种情况下,如果我将事务保存在A行中,然后再次保存在B行中,该如何回滚?
第3个问题 我可以看到将整个内容包装在try..catch块中将有什么帮助,但是我想知道是否有必要-我可以添加一些全局异常过滤器以仅返回友好消息,但严格来说是在事务状态方面,以下准确信息(如果没有,您是否建议您更适当/明智地进行):
我不必在每个控制器的每个操作中都必须处理与数据库相关的异常,因为最终错误将导致DbContext自动回滚所有内容(除非我多次调用SaveChanges在我的问题2中提到)。
谢谢!