如果在数据库中找不到记录,是否返回(RecordNotFound)异常或null

本文关键字:RecordNotFound 异常 null 返回 是否 数据库 找不到 记录 如果 | 更新日期: 2023-09-27 18:04:14

我真的不确定在处理数据库中找不到的记录时,首选的方法是什么。写返回null的Find方法更好还是写返回RecordNotFoundException的Get方法更好?

[AuthenticateFilter(UsernameAndSecretKey)]
[Route("api/v1/activities/emails/{id}")]
[HttpGet]
public IHttpActionResult GetEmailActivity(int id)
{
  try
  {
    // business logic service, could use only db service but this way we can do unit tests (just fill bl service method with fake objects)
    var service = new EmailActivityBlService();
    // 1. use Find method which returns null in case record with provided id does not exist in db
    var model = service.FindActivity(id);
    if( model != null )
      return Ok(model);
    return NotFound();  
   // 2. or is this approach better
   // throws RecordNotFoundException in case row by id is not found in database
   return Ok(service.GetActivity(id));
  }
  catch(RecordNotFoundException e) { return NotFound(); }
  catch(Exception e) { return InternalServerError(e); }
}

EmailActivityBlService有下一个代码,以防有人感兴趣(只显示重要部分(:

private EmailActivityDbService _dbService;
public EmailActivityModel GetActivity(int id)
{
  var model = this._dbService.GetActivity(id);
  if( model == null )
    throw new RecordNotFoundException(); // I suppose System.Data.ObjectNotFound is also suitable
  return model;
}
public EmailActivityModel FindActivity(int id)
{
  // typical entity framework query
  // using(var context = new ..) { return contect.EmailActivity.Where()..SingleOrDefault().ConvertToModel();
  return this._dbService.GetActivity(id);
}

更新

与我的同事交谈后,我们决定采用这个解决方案。至于为什么GetActivity返回null而不是抛出Exception,我更喜欢rboe的答案:

因此,如果是,则返回null。这可能发生在您的域中,即记录不存在(根据我的经验,这种情况最常见(。如果您希望记录存在,但它不存在,那么抛出异常是有效的。

[AuthenticateFilter(UsernameAndSecretKey)]
[Route("api/v1/activities/emails/{id}")]
[HttpGet]
public IHttpActionResult GetEmailActivity(int id)
{
   var service = new EmailActivityBlService();
   var model = service.GetActivity(id); // returns null in case activity is not found
   if( model != null )
     return Ok(model);
   return NotFound();
}

我们避免了方法中的任何try-catch,并在出现异常时设置全局筛选器:

文件:App_Start''WebApiConfig.cs

public class WebApiExceptionFilter : ExceptionFilterAttribute
{
  public override void OnException(HttpActionExecutedContext actionExecutedContext)
  {
    actionExecutedContext.Response = actionExecutedContext.Request.CreateErrorResponse(HttpStatusCode.InternalServerError, actionExecutedContext.Exception.Message, actionExecutedContext.Exception);
  }
}

如果在数据库中找不到记录,是否返回(RecordNotFound)异常或null

这两种方式都是有效的。

无论使用异常还是返回值null来表示不存在的记录,重点都不同。

存在异常以表示错误状态(发生了异常情况(。catch处理程序中的代码集中于如何处理错误而不包含业务逻辑。

如果返回null,那么它将是模型中的正常和"非异常"状态。

因此,如果在您的域中可能发生这种情况,则返回null,即记录不存在(根据我的经验,这种情况最常见(。如果您希望记录存在,但它不存在,那么抛出exception是有效的。

我不同意另一个答案。在GetyById方法的情况下,我不会说返回null而不是抛出,因为你可能会认为"预期"可能没有具有请求id的记录。这种"特殊情况下的例外"虽然经常被提及,但我真的不认为是思考该方法的合同的最佳方式。理想情况下,API应该具有语义意义。

相反,我建议在方法无法执行命令时抛出异常。因此,如果系统中没有具有请求id的记录,GetById方法应该抛出异常。Find方法可能应该返回一个可枚举值,当然,如果没有符合给定条件的记录,该值可能为空。

一个有FindById方法的API让我觉得很奇怪;如果你给API一个ID,这意味着调用者可能已经在以前的API调用中学习了ID,因此API不需要"找到"一个已知存在的记录。它应该提供一种直接通过id获取记录的方法。相反,Find应该用于在您不确定记录是否存在时定位记录,并使用其他一些标准。

给定web服务调用,我将使用调用GetById方法的服务,因为web服务调用方也不知何故了解了id。如果id不存在,库可以抛出RecordNotFoundException,这将导致服务调用返回404。