【发布时间】:2018-10-26 09:29:35
【问题描述】:
编辑:
我刚刚意识到 SaveChangesAsync 返回 0 并不意味着它失败了,实体框架在失败时总是会抛出异常,因此检查 SaveChanges == 0 是否是多余的!在下面的示例中,保存更改应始终返回 1,如果失败则抛出异常。
但是在某些情况下,使用了其他东西并且它不是实体框架,所以这个问题也是如此。
服务器可能会出现故障,当我将所有数据访问代码放入控制器时,我可以这样处理:
[HttpPost]
public async Task<ActionResult<Item>> CreateAsync([FromBody] Item item)
{
await _dbContext.AddAsync(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return CreatedAtAction(nameof(GetAsync), new { id = item.Id }, item);
}
当我的数据访问被封装在服务层时,我应该如何处理?
public class ItemsService
{
public async Task<Item> CreateAsync(Item item)
{
await _dbContext.AddAsync(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
return null;
}
return item;
}
}
那么它会这样使用:
[HttpPost]
public async Task<ActionResult<Item>> CreateAsync([FromBody] Item item)
{
// model state validation skipped for the sake of simplicity,
// that would return BadRequest or some more valuable information
var item = await _itemsService.CreateAsync(item);
if (item == null)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return CreatedAtAction(nameof(GetAsync), new { id = item.Id }, item);
}
也许这适用于精细创建,因为只有 2 个状态代码,但让我们考虑更新可能有超过 2 个可能错误的地方,例如:
- 未找到 (404)
- 内部服务器错误(500)
- 好的 (200)
没有服务的代码:
[HttpPut("{id}")]
public async Task<ActionResult<Item>> UpdateAsync(int id, [FromBody] Item itemToUpdate)
{
var item = await _dbContext.Items.FindAsync(id);
if (item == null)
{
return NotFound();
}
// update item with itemToUpdate
//...
await _dbContext.Update(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return item;
}
现在服务无法正确处理:
public class ItemsService
{
public async Task<Item> UpdateAsync(Item updateItem)
{
var item = await _dbContext.Items.FindAsync(id);
if (item == null)
{
return null;
}
//change some properties and update
//...
_dbContext.Items.Update(item);
if (await _dbContext.SaveChangesAsync() == 0)
{
// what now?
}
return item;
}
}
因为它总是返回 null 并且无法判断该项目是否未找到或保存失败。
如何正确处理?
注意:我没有添加 DTO 或类似的东西来保持这个例子的简单。
【问题讨论】:
-
你有没有想过会冒泡层而不是返回值的异常来解决硬件/io/传输特定问题,例如“互联网/服务器不可用”、“磁盘已满”
-
@k3b 你的意思是在 try-catch 中包装代码吗?或者你到底是什么意思?
标签: c# asp.net-core domain-driven-design entity-framework-core asp.net-core-webapi