我正在使用AutoFac在我的Web应用程序中注入具体的数据上下文。如果页面上没有例外,我想在请求结束时执行数据库上下文的SaveChanges()
方法。否则我只想正常处理上下文。
我注意到AutoFac有一个OnRelease
方法。该方法的Intellisense说明:
运行提供的操作,而不是在不再需要实例时处理它们。
因此,我正在考虑做这样的事情:
builder.RegisterType<MyContext>().As<IDbContext>().InstancePerHttpRequest()
.OnRelease(x => {
if (HttpContext.Current != null && HttpContext.Current.Error == null)
x.SaveChanges();
if (x != null)
{
x.Dispose();
x = null;
}
});
这是否适合提交数据上下文的更改?它是否可以保证在每个请求上运行,即使出现异常?
答案 0 :(得分:2)
一般情况下,我不喜欢在请求结束时保存更改的方法,因为这会失去灵活性。好的做法是保存业务交易结束时的变更。想象一下这个示例代码:
public ActionResult CreateAccount(CreateAccountModel createAccountModel)
{
// Your business transaction start here from validating and processing input data
var account = CreateAccountFrom(createAccountModel);
_yourContext.Add(account);
// Your business transaction ends here
// This is the good place to commit your transaction
_yourContext.SaveChanges();
// You can have another business transaction here
// the following is not important code to log the event
// which could break the business transaction if it would be within one
// you can wrap it in try-catch for example
_yourContext.Add(new Event(){ Type = AccountCreated });
_yourContext.SaveChanges();
// code to retrieve date for the view
var viewModel = GetViewModel();
return View(viewModel);
}
现在关于你的代码,简而言之,它是一个保存更改的好地方。首先,你违反了单一责任原则,OnRelease应该在没有IDisposable的类上清理资源,但不要做其他逻辑。将业务逻辑放在那里只是因为你可以做到这一点是不好的。第二件事,如果你在x.SaveChanges()上得到一个例外,你的上下文就不会被处理掉。最好不要弄乱业务逻辑和对象生命周期逻辑。
答案 1 :(得分:0)
我同意亚历山大关于这是一个糟糕地方的结论,但我不同意他背后的理由。
我之所以不想这样做,是因为您的请求将结束并返回200响应。 OnRelease大概会在另一个线程上被调用,如果失败,那么您就不应该使用状态代码了。
EF本质上实现了工作单元模式,因此IMO不需要在任何地方调用保存更改。在请求结束时,保存一次就足够了。
我也不会在控制器方法上调用它,尤其是在大多数或所有控制器都访问dbcontext的情况下。 相反,您可以创建一个动作过滤器并将其全局连接。
这是一个.net核心示例:
public class SaveChangesFilter : IActionFilter
{
private readonly ILogger<SaveChangesFilter> _logger;
private readonly DbContext _dbContext;
public SaveChangesFilter(IDbContext dbContext, ILogger<SaveChangesFilter> logger)
{
_logger = logger;
_dbContext = dbContext as DbContext;
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (_dbContext.ChangeTracker.HasChanges())
{
try
{
_dbContext.SaveChanges();
}
catch (Exception e)
{
context.Result = <insert error response here>
_logger.LogCritical(e, e.Message);
}
finally
{
_dbContext.Dispose();
}
}
}
}
然后在应用程序启动的ConfigureServices方法中:
services.AddMvc(options =>
{
options.Filters.Add<SaveChangesFilter>();
})