C# 在较长的数据上下文或上下文之外的事务之间进行权衡?

C# 在较长的数据上下文或上下文之外的事务之间进行权衡?,c#,entity-framework,asp.net-web-api,transactions,C#,Entity Framework,Asp.net Web Api,Transactions,我正在编写一个WebAPI Rest服务,它对一组不同的实体进行操作。我把它们分解成这样: db = new DBEntities(); using (var dbContextTransaction = db.Database.BeginTransaction()) { try { ProcessClient(); ProcessCl

我正在编写一个WebAPI 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();
        ....
这显然不起作用-以这种方式创建的事务上下文与数据上下文绑定。如果某个实体操作出错,则只回滚该操作(隐式),而不回滚总体事务

我发现了这一点,但我想知道是应该遵循它,还是应该让我的数据上下文在事务期间保持有效,并将事务保持在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
   }
}
关于锁定的感觉很复杂,因为在我的开发虚拟机上,事务运行1-2秒,这是一个生产数据库,办公室工作人员和在线客户同时通过web应用程序执行CRUD事务

不相关,但对我的AddOrUpdate方法很有帮助