代码之家  ›  专栏  ›  技术社区  ›  David

如何使用依赖注入将工作单元容器传递到存储库的构造函数中

  •  4
  • David  · 技术社区  · 14 年前

    我正在尝试解决如何在ASP.NET web应用程序中完成存储库模式的实现。

    每个存储库接口都由一个执行NHibernate工作的类实现。Castle Windsor根据web.config将类的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();
            }
          }
        }
      }
    

    再次感谢你的建议。

    大卫

    3 回复  |  直到 14 年前
        1
  •  1
  •   Neil Hewitt    14 年前

    IRepository IRepository<T>

    由于Unity不支持(或者至少我正在使用的版本不支持)传入构造函数参数,而不是依赖注入本身,因此传入现有的nhisession是不可能的;但我确实希望UOW中的所有对象共享同一个会话。

    我通过拥有一个控制存储库类来解决这个问题,该类在每个线程的基础上管理对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 访问 IList<object> 或者 ThreadStatic 如果不是在Web上下文中,或者 HttpContext.Current.Items ISession 从存储的工厂实例,后续调用只从存储中检索它。锁定会稍微减慢速度,但不会像锁定appdomain范围的静态文件那样慢 ISession公司 实例。

    BeginUnitOfWork EndUnitOfWork 处理UOW的方法-我特别不允许嵌套UOW,因为坦率地说,管理它们是件痛苦的事。

        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();
                }
            }
        }
    

        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>();
        }
    

    (这里, PersistentObject<T>

    因此,对给定存储库的访问是

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

    然后将其覆盖,以便您可以使用

    MyDomainType.Repository.Save();
    

    一个给定的类型有一个专门的存储库(即需要的比它能从中得到的更多) )然后我创建了一个从 i假定<T> ,一个从我的 Repository new

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

    MyApplication [在实际产品中被称为不那么noddy的东西]是一个facade类,负责提供 存储库 通过Unity创建实例,因此您不依赖域类中特定的NHibernate存储库实现。)

    ISession公司 管理层。

    这里的代码比上面的要多得多(我已经将示例代码简化了很多),但是您可以理解其中的大意。

    MyApplication.Repository.BeginUnitOfWork();
    User user = User.Repository.FindByEmail("wibble@wobble.com");
    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应用程序中,每个请求都有会话,所以 开始工作 工作结束单位 被叫进来 BeginRequest EndRequest 分别。

        2
  •  0
  •   rebelliard    14 年前

    1) 要在每个方法上指定容器,我有一个单独的类(“ SessionManager )然后通过静态属性调用。通过这样做,下面是一个使用我的Save实现的示例:

    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;
    }
    

    global.asax 第页。

    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);
    
        3
  •  0
  •   David    14 年前

    从技术上讲,我的问题的答案是使用container.Resolve的重载,它允许您将构造函数参数指定为匿名类型:

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