我正在编写一个Web API Rest服务,它在一组不同的实体上执行操作。我把它们打破了这样:
db = new DBEntities();
using (var dbContextTransaction = db.Database.BeginTransaction())
{
try
{
ProcessClient();
ProcessClientPerson();
ProcessGuardian();
ProcessAddress();
ProcessEmail();
ProcessPhones();
ProcessChildren();
dbContextTransaction.Commit();
}
catch (Exception ex)
{
dbContextTransaction.Rollback();
etc.
遵循数据上下文应尽可能短的建议,每个方法都创建自己的数据上下文,调用SaveChanges(),并在最后处置它:
private ProcessClient()
{
db = new DBEntities();
....
这显然不起作用 - 以这种方式创建的事务上下文与数据上下文相关联。如果其中一个实体操作出现问题,那么只会回滚(隐式)该操作,但总体事务不会回滚。
我发现了这个approach for creating a transaction outside of EF,但我想知道我是否应该遵循它,或者我是否应该在交易期间让我的数据上下文生效并将交易保留在EF中??
我不是在寻找意见,而是寻找有关稳定性,性能等的数据
答案 0 :(得分:1)
没有立即需要保持上下文的短命。您可以这样做,但您不必这样做。
随着时间的推移,实体将在上下文中累积。如果您冒着内存不足的风险,可能需要放开上下文。
否则,通常的过程是在逻辑工作单元的持续时间内使上下文保持活动状态。在这里,UOW就是完整的所有方法。
这也使事务管理变得更容易(正如您已经发现的那样)。
dbContextTransaction.Rollback();
这是一种反模式。如果出现错误,请不要提交。
答案 1 :(得分:0)
我对此感到复杂。我正在处理没有外键约束的遗留数据库,我在其中一个服务调用中插入,更新和删除20到30个对象。
问题是我需要经常调用SaveChanges()来获取将成为外键的标识列值。
另一方面,如果出现三层故障,我必须能够回滚所有内容,因此需要一个大型事务。
由于某些我无法确定的原因,在相同的数据上下文中重复调用SaveChanges会导致连接状态打开的错误。所以我最终还是为每个方法提供了自己的数据上下文:
var scope = new TransactionScope(TransactionScopeOption.RequiresNew,
new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted);
using (scope)
{
try
{
ProcessClient();
ProcessClientPerson();
ProcessGuardian();
ProcessAddress();
ProcessEmail();
ProcessPhones();
ProcessChildren();
scope.Complete();
}
catch (System.Data.Entity.Validation.
DbEntityValidationException ex)
{
[...] handle validation errors etc [...]
}
}
每个部分基本上都是这样做的,一旦被剥离到最基本的要点:
private void ProcessClient() {
{
using (MyDBEntities db = new MyDBEntities())
{
[...] doing client stuff [...]
aClient.LastUpdated = DateTime.Now;
db.AddOrUpdate(db, db.Clients, aClient, aClient.ClientID);
db.SaveChanges();
ClientId = aClient.ClientID; // now I can use this to form FKs
}
}
关于锁定的复杂感觉,因为在我的开发虚拟机上,事务运行1-2秒,这是一个生产数据库,办公人员和在线客户同时通过Web应用程序进行CRUD交易。
不相关,但对我的AddOrUpdate方法was this blog post很有帮助。