【问题标题】:Trade-offs between longer data context or transaction outside of context?更长的数据上下文或上下文之外的事务之间的权衡?
【发布时间】:2016-03-06 00:14:47
【问题描述】:

我正在编写一个 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 中!?

我不是在寻找意见,而是在寻找有关稳定性、性能等方面的数据。

【问题讨论】:

    标签: c# entity-framework asp.net-web-api transactions


    【解决方案1】:

    没有立即需要使上下文保持短暂的状态。你可以这样做,但你不必这样做。

    随着时间的推移,实体会在上下文中累积。如果您冒着内存不足的风险,则可能需要放弃上下文。

    否则,通常的过程是在逻辑工作单元的持续时间内使上下文保持活动状态。在这里,UOW 就是所有这些方法的全部。

    这也使事务管理更容易(正如您已经发现的那样)。

    dbContextTransaction.Rollback();

    这是一种反模式。万一出错就不要提交。

    【讨论】:

      【解决方案2】:

      我对此有复杂的感觉。我正在处理一个没有外键约束的旧数据库,并且在其中一个服务调用中插入、更新和删除 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

      【讨论】:

        猜你喜欢
        • 2011-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 2016-05-20
        • 2015-12-01
        相关资源
        最近更新 更多