【问题标题】:Object Context, Repositories and Transactions对象上下文、存储库和事务
【发布时间】:2009-06-29 00:22:03
【问题描述】:

我想知道在实体框架中使用事务的最佳方式是什么。

假设我有三个存储库:

 Repo1(ObjectContext context)
 Repo2(ObjectContext context)
 Repo3(ObjectContext context)

以及一个接受三个存储库的服务对象:

 Service(Repo1 repo1,Repo2 repo2, Repo3 repo3)
 Serive.CreateNewObject <- calls repo1, repo2, repo3 to do stuff.

因此,当我创建服务时,我首先创建了三个存储库并将它们传递下去,每个存储库都有一个对象上下文,因此我的代码如下所示:

MyObjectContext context = new MyObjectContext();
Repo1 repo = new Repo1(context);
// etc

现在我有一个控制器类,它负责调用我的应用程序的不同服务和组件,显示正确的表单等。现在我想要做的是将发生在控制器方法之一中的所有内容包装在一个事务,这样如果出现问题我可以回滚。

控制器接受几个不同的服务对象,但对对象上下文一无所知。

我的问题是:

  1. 是否也应将上下文传递到服务层。
  2. 如何在控制器中实现事务,以便服务中发生的任何事情 在一切都过去之前,不会提交层。

对不起,如果有点难以理解..

【问题讨论】:

    标签: c# entity-framework transactions


    【解决方案1】:

    为什么你的控制器不知道 ObjectContext?

    这就是我要放的地方。查看 - http://msdn.microsoft.com/en-us/magazine/dd882510.aspx - 这里的命令将提交/回滚 UnitOfWork(ObjectContext)。

    如果您不想让控制器确切地了解 EF(良好的设计),那么您希望将 ObjectContext 抽象为与上述链接中的方法类似的接口。 p>

    【讨论】:

      【解决方案2】:

      使用自定义的 TransactionScope 怎么样,当您的所有服务都已提交时提交?

      public class TransactionScope : Scope<IDbTransaction>
      {
          public TransactionScope()
          {
              InitialiseScope(ConnectionScope.CurrentKey);
          }
      
          protected override IDbTransaction CreateItem()
          {
              return ConnectionScope.Current.BeginTransaction();
          }
      
          public void Commit()
          {
              if (CurrentScopeItem.UserCount == 1)
              {
                  TransactionScope.Current.Commit();
              }
          }
      }
      

      所以只有当 UserCount 为 1 时才会提交事务,这意味着最后一个服务已经提交。

      范围类是(可惜我们不能做附件...):

      public abstract class Scope<T> : IDisposable
          where T : IDisposable
      {
          private bool disposed = false;
      
          [ThreadStatic]
          private static Stack<ScopeItem<T>> stack = null;
      
          public static T Current
          {
              get { return stack.Peek().Item; }
          }
      
          internal static string CurrentKey
          {
              get { return stack.Peek().Key; }
          }
      
          protected internal ScopeItem<T> CurrentScopeItem
          {
              get { return stack.Peek(); }
          }
      
          protected void InitialiseScope(string key)
          {
              if (stack == null)
              {
                  stack = new Stack<ScopeItem<T>>();
              }
      
              // Only create a new item on the stack if this
              // is different to the current ambient item
              if (stack.Count == 0 || stack.Peek().Key != key)
              {
                  stack.Push(new ScopeItem<T>(1, CreateItem(), key));
              }
              else
              {
                  stack.Peek().UserCount++;
              }            
          }
      
          protected abstract T CreateItem();
      
          public void Dispose()
          {
              Dispose(true);
          }
      
          protected virtual void Dispose(bool disposing)
          {
              if (!disposed)
              {
                  if (disposing)
                  {
                      // If there are no users for the current item
                      // in the stack, pop it
                      if (stack.Peek().UserCount == 1)
                      {
                          stack.Pop().Item.Dispose();
                      }
                      else
                      {
                          stack.Peek().UserCount--;
                      }
                  }
      
                  // There are no unmanaged resources to release, but
                  // if we add them, they need to be released here.
              }
      
              disposed = true;
          }
      }
      
      public class ScopeItem<T> where T : IDisposable
      {
          private int userCount;
          private T item;
          private string key;
      
          public ScopeItem(int userCount, T item, string key)
          {
              this.userCount = userCount;
              this.item = item;
              this.key = key;
          }
      
      
          public int UserCount
          {
              get { return this.userCount; }
              set { this.userCount = value; }
          }
      
          public T Item
          {
              get { return this.item; }
              set { this.item = value; }
          }
      
          public string Key
          {
              get { return this.key; }
              set { this.key = value; }
          }
      }
      
      public class ConnectionScope : Scope<IDbConnection>
      {
          private readonly string connectionString = "";
          private readonly string providerName = "";
      
          public ConnectionScope(string connectionString, string providerName)
          {
              this.connectionString = connectionString;
              this.providerName = providerName;
      
              InitialiseScope(string.Format("{0}:{1}", connectionString, providerName));
          }
      
          public ConnectionScope(IConnectionDetailsProvider connectionDetails)
              : this(connectionDetails.ConnectionString, connectionDetails.ConnectionProvider)
          {
          }
      
          protected override IDbConnection CreateItem()
          {
              IDbConnection connection = DbProviderFactories.GetFactory(providerName).CreateConnection();
              connection.ConnectionString = connectionString;
              connection.Open();
              return connection;
          }
      }
      

      【讨论】:

        【解决方案3】:

        将操作包装在 TransactionScope 中。

        【讨论】:

          【解决方案4】:

          您可能希望实现 Workflow Foundation 使用的事务模型。它基本上有一个所有“组件”都实现的接口。在每个成功完成主要工作后,主机调用每个上的“提交”方法。如果一个失败,它会调用“回滚”方法。

          【讨论】:

            猜你喜欢
            • 2011-07-04
            • 1970-01-01
            • 2019-01-16
            • 1970-01-01
            • 2012-10-25
            • 1970-01-01
            • 1970-01-01
            • 2023-03-31
            • 1970-01-01
            相关资源
            最近更新 更多