在更长的数据上下文或上下文之外的事务之间进行权衡?
Trade-offs between longer data context or transaction outside of context?
我正在编写一个 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 中!?
我不是在寻找意见,而是在寻找有关稳定性、性能等方面的数据
没有立即需要保持上下文短暂存在。你可以这样做,但你不必这样做。
随着时间的推移,实体将在上下文中积累。如果您冒 运行 内存不足的风险,则可能有必要放弃上下文。
否则,通常的过程是在逻辑工作单元的持续时间内保持上下文活动。在这里,UOW 就是所有这些方法的全部。
这也使事务管理更容易(正如您已经发现的那样)。
dbContextTransaction.Rollback();
这是一个反模式。万一出错就不要提交。
对此,我百感交集。我正在处理没有外键约束的遗留数据库,并且我在其中一个服务调用中插入、更新和删除了 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
}
}
对锁定的感觉很复杂,因为在我的开发 VM 上事务运行 1-2 秒,这是一个生产数据库,办公室人员和在线客户同时通过 Web 应用程序进行 CRUD 事务。
无关,但对我的 AddOrUpdate 方法有帮助 was this blog post。
我正在编写一个 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 中!?
我不是在寻找意见,而是在寻找有关稳定性、性能等方面的数据
没有立即需要保持上下文短暂存在。你可以这样做,但你不必这样做。
随着时间的推移,实体将在上下文中积累。如果您冒 运行 内存不足的风险,则可能有必要放弃上下文。
否则,通常的过程是在逻辑工作单元的持续时间内保持上下文活动。在这里,UOW 就是所有这些方法的全部。
这也使事务管理更容易(正如您已经发现的那样)。
dbContextTransaction.Rollback();
这是一个反模式。万一出错就不要提交。
对此,我百感交集。我正在处理没有外键约束的遗留数据库,并且我在其中一个服务调用中插入、更新和删除了 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
}
}
对锁定的感觉很复杂,因为在我的开发 VM 上事务运行 1-2 秒,这是一个生产数据库,办公室人员和在线客户同时通过 Web 应用程序进行 CRUD 事务。
无关,但对我的 AddOrUpdate 方法有帮助 was this blog post。