我不确定在处理数据库中找不到的记录时,首选方法是什么。编写返回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);
}
}
答案 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.