Nhibernate,WinForms,Castle Windsor:会话管理

时间:2010-08-19 12:38:47

标签: c# winforms nhibernate castle-windsor session-management

我知道会话管理的问题在过去已经提出,但我找不到任何可以帮助我解决问题的事情。

我有许多存储库类(例如CustomerRepository,ProductRepository等),我通过Castle Windsor解析(注意:我正在尝试应用三个调用模式here)。我想我最好每个Presenter有一个会话(在我的情况下,这相当于每个表单一个),但是,存储库类需要访问当前活动表单的会话..我不知道我是如何合并这个事实上这些存储库是通过windsor解决的,因为主持人不是单身人士。

例如:

public class SomePresenter
{
  private ISomeView view;
  private ISession session;
  private ICustomerRepository customerRepository;
  private IOrderRepository orderRepository;

  public SomePresenter(ISomeView view, ISessionFactory sessionFactory, ICustomerRepository customerRepository, IOrderRepository orderRepository)
  {
    this.view = view;
    this.session = sessionFactory.OpenSession();
    this.customerRepository = customerRepository;
    this.orderRepository = orderRepository;
  }
}

存储库需要访问会话...如何使用Windsor进行此操作?我是否被迫通过属性在存储库中手动设置会话,还是有一个我不熟悉的聪明的温莎技巧?

2 个答案:

答案 0 :(得分:4)

为什么不将[{1}}注入您的存储库而不是ISession

以下是与Autofac一起使用的类似代码,Autofac是一个不同的IoC容器:

ISessionFactory

其中containerBuilder .Register(c => NHibernateContext.GetSessionFactory().OpenSession()) .As<ISession>() .InstancePerLifetimeScope(); 是我唯一一个配置NHibernate并保留在NHibernateContext单例上的静态类。

所以我的存储库/查找对象请求会话:

ISessionFactory

然后我的Presenter / View Model / Superivsing Controller / Whatever-The-Heck -oday-Calling-It-This-Month只获取存储库或查找对象:

public MyRepository(ISession session)
{
    this.session = session;
}

对于Windsor,我认为(我对它的API非常熟悉,你可能不得不调整它,但它应该给你一个想法)它会像

public MyPresenter(IWhateverRepository repository)
{
     // Look ma, the repository has an ISession and I'm none the wiser!
}

也就是说,你告诉容器,“当有人要求ISession时,运行这个获得container.Register( Component.For<ISession> .UsingFactoryMethod( x => x.Resolve<ISessionFactory>().OpenSession()) .LifeStyle.Transient); 的小代理并打开一个会话,然后给他们ISessionFactory实例。”

但谁关闭ISession?这取决于您:您可以让存储库在其自己的ISession方法中明确关闭ISession。或者你可以依靠你的容器进行关闭和处理;在Autofac中,我使用Dispose()ILifetimeScope执行此操作;在Windsor,我相信你需要查找嵌套容器,这样当你处理一个子容器时,它所创建的所有组件也会被处理掉。

根据我的经验,这通常意味着容器至少泄漏到我的应用程序的“主要形式”:当创建表单时,它会创建一个新的生命周期范围/嵌套容器并显示表单。但是这个级别以下的任何东西都不知道容器;它只是围绕一组组件扔套索,并说“当表格关闭时,摆脱所有这些。”

(这是为了防止在大多数应用程序中使用一个大的鸣笛InstancePerLifetimeScope()。这在ASP.NET中工作正常,每个请求一个会话,但在Windows窗体中,正如您所说,它是就像陈旧的对象例外的定时炸弹一样。更好地为每个“工作单元”(通常是每个表单或服务)拥有自己的ISession。)

您也可以设计您的存储库,以便每个方法都需要传入ISession,但这似乎会变得乏味。

希望能给你一些想法。祝你好运!

答案 1 :(得分:1)

为什么不为每个演示者/控制器提供一个SessionProvider个人Data Access Objects(DAO)?您的模型可通过每个Data Access Object访问。

public sealed class SessionProvider
{
        static readonly SessionProvider provider = new SessionProvider();
        private static NHibernate.Cfg.Configuration config;
        private static ISessionFactory factory;
        static ISession session = null;

        /// <summary>
        /// Initializes the <see cref="SessionProvider"/> class.
        /// </summary>
        static SessionProvider() { }

        /// <summary>
        /// Gets the session.
        /// </summary>
        /// <value>The session.</value>
        public static ISession Session
        {
            get
            {
                if (factory == null)
                {
                    config = new NHibernate.Cfg.Configuration();
                    config.Configure();

                    factory = config.BuildSessionFactory();
                }

                if (session == null)
                {                   
                    if (config.Interceptor != null)
                        session = factory.OpenSession(config.Interceptor);
                    else
                        session = factory.OpenSession();
                }

                return session;
            }
        }
    }

public sealed class OrderDataControl
{

        private static ILog log = LogManager.GetLogger(typeof(OrderDataControl));

        private static OrderDataControl orderDataControl;
        private static object lockOrderDataControl = new object();
        /// <summary>
        /// Gets the thread-safe instance
        /// </summary>
        /// <value>The instance.</value>
        public static OrderDataControl Instance
        {
            get
            {
                lock (lockOrderDataControl)
                {
                    if (orderDataControl == null)
                        orderDataControl = new OrderDataControl();
                }
                return orderDataControl;
            }           
        }

        /// <summary>
        /// Gets the session.
        /// </summary>
        /// <value>The session.</value>
        private ISession Session
        {
            get
            {
                return SessionProvider.Session;                
            }
        }


        /// <summary>
        /// Saves the specified contact.
        /// </summary>
        /// <param name="contact">The contact.</param>
        /// <returns></returns>
        public int? Save(OrderItems contact)
        {
            int? retVal = null;
            ITransaction transaction = null;

            try
            {
                transaction = Session.BeginTransaction();
                Session.SaveOrUpdate(contact);

                if (transaction != null && transaction.IsActive)
                    transaction.Commit();
                else
                    Session.Flush();

                retVal = contact.Id;
            }
            catch (Exception ex)
            {
                log.Error(ex);
                if (transaction != null && transaction.IsActive)
                    transaction.Rollback();
                throw;
            }

            return retVal;
        }