4

我正在嘗試解決如何在ASP.NET Web應用程序中完成我的倉庫模式實現。如何使用依賴注入將工作單元容器傳遞到存儲庫的構造函數

此刻,我有一個每個域類的存儲庫接口定義方法,例如,加載和保存該類的實例。

每個存儲庫接口是由一個類來實現NHibernate的東西。根據web.config,Castle Windsor將類的DI排序到界面中。一個實現類的例子提供如下:

public class StoredWillRepository : IStoredWillRepository 
    { 
    public StoredWill Load(int id) 
    { 
     StoredWill storedWill; 
     using (ISession session = NHibernateSessionFactory.OpenSession()) 
     { 
     storedWill = session.Load<StoredWill>(id); 
     NHibernateUtil.Initialize(storedWill); 
     } 
     return storedWill; 
    } 

    public void Save(StoredWill storedWill) 
    { 
     using (ISession session = NHibernateSessionFactory.OpenSession()) 
     { 
     using (ITransaction transaction = session.BeginTransaction()) 
     { 
      session.SaveOrUpdate(storedWill); 
      transaction.Commit(); 
     } 
     } 
    } 
    } 

正如在先前的線程所指出的,存儲庫類需要接受工作容器的單元(即ISession的)而不是在每個方法實例化它。

我預計工作單元容器將在需要時由每個aspx頁面創建(例如,屬性中)。

那麼我怎麼才能指定這個工作單元的容器實例是在Windsor爲我創建時傳入StoredWillRepository的構造函數?

或者是這種模式完全錯誤?

再次感謝您的建議。

大衛

回答

0

技術上,回答我的問題是使用container.Resolve的過載,它允許您指定構造器參數的匿名類型:

IUnitOfWork unitOfWork = [Code to get unit of work]; 
_storedWillRepository = container.Resolve<IStoredWillRepository>(new { unitOfWork = unitOfWork }); 

但是讓我們面對現實吧,答案由大家提供其他方面的信息也更多。

+0

就像你所說,這就是技術上對我的問題的答案,即使不是最佳的解決方案。我正在打勾你。 – David 2010-11-04 14:51:20

0

我有一個非常相似的結構,以你的,這裏是我如何解決你的問題:

1)要指定我的容器上的每一個方法,我有一個單獨的類(「SessionManager」)然後我通過一個靜態屬性調用它。通過這樣做,下面是使用我的保存實現的示例:

private static ISession NHibernateSession 
{ 
    get { return SessionManager.Instance.GetSession(); } 
} 

public T Save(T entity) 
{ 
    using (var transaction = NHibernateSession.BeginTransaction()) 
    { 
     ValidateEntityValues(entity); 
     NHibernateSession.Save(entity); 

     transaction.Commit(); 
    } 

    return entity; 
} 

2)我的容器並未在每個ASPX頁面上創建。我在global.asax頁面實例化了我所有的NHibernate善良。

**一些事情冒出來**

3)你並不需要一個幫手來實例化加載。你可以使用Get而不是Load。更多信息@Difference between Load and Get。 4)使用你當前的代碼,你將不得不爲每個需要的域對象(StoredWillRepository,PersonRepository,CategoryRepository等)重複相同的代碼,這看起來像一個拖動。你很可能使用generic class了NHibernate的操作,如:

public class Dao<T> : IDao<T> 
{ 
    public T SaveOrUpdate(T entity) 
    { 
     using (var transaction = NHibernateSession.BeginTransaction()) 
     { 
      NHibernateSession.SaveOrUpdate(entity); 
      transaction.Commit(); 
     } 

     return entity; 
    } 
} 

在我的實現,我可以再使用something like

Service<StoredWill>.Instance.SaveOrUpdate(will); 
+0

非常感謝您的意見。我將在以下編號註釋中迴應您的觀點: – David 2010-07-23 13:45:56

+0

1)靜態ISession?除非我誤解,否則這意味着ISession(不是線程安全的)在應用程序的所有線程之間共享 - 非常危險。這是不正確的? – David 2010-07-23 13:46:45

+0

2)什麼容器?對不起,我沒有看到你的意思。 – David 2010-07-23 13:47:20

1

我必須建立在NHibernate的頂部的持久性框架,在幾個Web應用程序中使用。它將NH實現隱藏在一個接口IRepositoryIRepository<T>接口後面,並提供了Unity提供的具體實例(因此我理論上可以相當容易地將NHibernate換成實體框架)。由於Unity不支持(或者至少我使用的版本不支持)構造函數參數的傳入,而不是那些依賴注入本身,所以傳遞一個現存的NH ISession是不可能的;但我確實希望UOW中的所有對象共享相同的ISession。

我通過具有管理上的每個線程的基礎訪問的ISession的控制信息庫類解決這個問題:

public static ISession Session 
    { 
     get 
     { 
      lock (_lockObject) 
      { 
       // if a cached session exists, we'll use it 
       if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY)) 
       { 
        return (ISession)PersistenceFrameworkContext.Current.Items[NHibernateRepository.SESSION_KEY]; 
       } 
       else 
       { 
        // must create a new session - note we're not caching the new session here... that's the job of 
        // BeginUnitOfWork(). 
        return _factory.OpenSession(new NHibernateInterceptor()); 
       } 
      } 
     } 
    } 

在這個例子中,PersistenceFrameworkContext.Current.Items訪問存儲要麼ThreadStatic如果不是在一個IList<object> Web上下文,或者在HttpContext.Current.Items之內(如果它位於Web上下文中)(以避免線程池問題)。對屬性的第一次調用從存儲的工廠實例中實例化ISession,隨後的調用只是從存儲中檢索它。該鎖定會稍微減慢速度,但不會像鎖定應用程序域的靜態ISession實例那樣。

然後我有BeginUnitOfWorkEndUnitOfWork方法來照顧UOW - 我已經明確地禁止嵌套的UOWs,因爲坦率地說,他們是一個痛苦的管理。

public void BeginUnitOfWork() 
    { 
     lock (_lockObject) 
     { 
      if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY)) 
       EndUnitOfWork(); 

      ISession session = Session; 
      PersistenceFrameworkContext.Current.Items.Add(SESSION_KEY, session); 
     } 
    } 

    public void EndUnitOfWork() 
    { 
     lock (_lockObject) 
     { 
      if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY)) 
      { 
       ISession session = (ISession)PersistenceFrameworkContext.Current.Items[SESSION_KEY]; 
       PersistenceFrameworkContext.Current.Items.Remove(SESSION_KEY); 
       session.Flush(); 
       session.Dispose(); 
      } 
     } 
    } 

最後,對方法提供訪問域類型特定庫:(這裏,PersistentObject<T>是一個基類提供ID和equals支持)

public IRepository<T> For<T>() 
     where T : PersistentObject<T> 
    { 
     return Container.Resolve<IRepository<T>>(); 
    } 

    public TRepository For<T, TRepository>() 
     where T : PersistentObject<T> 
     where TRepository : IRepository<T> 
    { 
     return Container.Resolve<TRepository>(); 
    } 

訪問給定的存儲庫因此處於該模式中

NHibernateRepository.For<MyDomainType>().Save(); 

然後這是facaded了,這樣你可以使用

MyDomainType.Repository.Save(); 

如果給定類型有一個專門的倉庫(即需要超過它可以從IRepository<T>獲得),那麼我創建一個接口,從IRepository<T>,延伸實現從我IRepository<T>實現繼承派生,並在域類型本身我重寫使用靜態Repository財產new

new public static IUserRepository Repository 
    { 
     get 
     { 
      return MyApplication.Repository.For<User, IUserRepository>(); 
     } 
    } 

MyApplication [這就是所謂的真正的產品的東西少諾迪]是一個門面類需要supplyi的護理通過Unity的Repository實例,所以你不需要依賴於你的領域類中具體的NHibernate存儲庫實現。)

這給了我完整的可插入性,通過統一資源庫的實現,在代碼中輕鬆訪問存儲庫而無需跳過環,並且透明,按線程ISession管理。

還有很多比上面的代碼更多的代碼(並且我已經簡化了示例代碼),但是您會得到一般想法。

MyApplication.Repository.BeginUnitOfWork(); 
User user = User.Repository.FindByEmail("[email protected]"); 
user.FirstName = "Joe"; // change something 
user.LastName = "Bloggs"; 
// you *can* call User.Repository.Save(user), but you don't need to, because... 
MyApplication.Repository.EndUnitOfWork(); 
// ...causes session flush which saves the changes automatically 

在我的Web應用程序,我有會話的每個請求,所以BeginUnitOfWorkEndUnitOfWork獲得分別稱爲BeginRequestEndRequest

+0

太棒了。我一定會檢查我的代碼是否可以使用你的一些善意。 xD – rebelliard 2010-07-23 14:41:06

+0

堆棧溢出需要一個按鈕'可能是正確的答案,但坦率地說,我不明白'。我會在這裏點擊它。我會盡量在週末消化它,但它可能是第二好喝醉了。至少我讚賞你的電子郵件地址! – David 2010-07-23 15:22:10

+0

喝醉是一個很棒的主意,我今天晚上要複製一下:-)至於代碼,所有間接和元編程的級別確實使得閱讀更難。我們的持久性框架的真正完整實現是關於我們庫中最複雜的代碼 - 但是一旦您完成了一次,您就再也不需要這樣做了。它多次爲自己支付。 – 2010-07-23 15:28:43

相關問題