返回(RecordNotFound)异常或如果在数据库中找不到记录则为null?

时间:2016-08-27 18:58:19

标签: c# exception-handling

我不确定在处理数据库中找不到的记录时,首选方法是什么。编写返回null的Get方法或返回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而不是抛出异常,我更喜欢 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);
  }
}

2 个答案:

答案 0 :(得分:4)

两种方式都是有效的。

您是否使用例外或返回值null来表示不存在的记录,这是一个不同的重点。

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

如果您返回null,那么这将是正常的,并且非特殊的'在你的模型中陈述。

因此,如果您的域中可能发生这种情况,则返回null,这些记录不存在(根据我的经验,这种情况通常是这种情况)。如果您希望记录存在且不存在,则抛出exception是有效的。

答案 1 :(得分:2)

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

相反,我建议每当方法无法按照要求执行操作时抛出异常。因此,如果系统中没有包含请求的id的记录,则GetById方法应抛出异常。 Find方法应该返回一个枚举,当没有记录符合给定的条件时,它当然可以为空。

具有FindById方法的API让我感到奇怪;如果你给API一个ID,这意味着调用者可能以某种方式在之前的API调用中学习了ID,因此API不需要“找到”已知的已存在记录。它应该提供一种直接通过其id获取记录的方法。相反,查找应该是在您不确定它们存在时使用其他标准来查找记录。

鉴于Web服务调用,我会使用调用GetById方法的服务,因为Web服务调用者也以某种方式学习了id。如果id不存在,则库可以抛出RecordNotFoundException,这会导致服务调用返回404.