2009-06-29 37 views
4

我想知道什麼是使用實體框架轉換的最佳方式。對象上下文,存儲庫和事務

說我有三個不同版本庫:

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. 如何在控制器中實施交易,以便發生在服務 層中的任何事情都無法完成,直到所有事情都已過。

很抱歉,如果這是一個有點難以理解..

回答

3

爲什麼你的控制器不知道ObjectContext?

這是我會說的地方。退房 - http://msdn.microsoft.com/en-us/magazine/dd882510.aspx - 這裏的命令是提交/回滾UnitOfWork(ObjectContext)的東西。

如果你不想讓你的控制器知道正好關於EF(好的設計),那麼你想要將你的ObjectContext抽象成類似於上述鏈接方法的接口。

+0

+1大文章! – Albic 2009-10-19 14:56:51

0

您可能要落實基礎工作流中使用的交易模式。它基本上有一個所有「組件」實現的接口。在主要工作成功完成之後,主機會在每個方法上調用「提交」方法。如果失敗了,它會調用「回滾」方法。

3

如何使用自定義的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; 
    } 
}