2

我知道过去曾提出过会话管理的问题,但我找不到任何可以帮助我克服问题的东西。

我有许多通过 Castle Windsor 解决的存储库类(例如 CustomerRepository、ProductRepository 等)(注意:我正在尝试应用此处概述的三种调用模式)。我想我最好每个 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 来解决这个问题?我是否被迫通过属性手动设置存储库上的会话,或者是否有一个我不熟悉的聪明的温莎技巧?

4

2 回答 2

4

为什么不直接将 an 注入ISession到您的存储库中而不是ISessionFactory?

下面是我在 Autofac(一个不同的 IoC 容器)中使用的类似代码:

containerBuilder
    .Register(c => NHibernateContext.GetSessionFactory().OpenSession())
    .As<ISession>()
    .InstancePerLifetimeScope();

NHibernateContext我的唯一一个配置 NHibernate 并保持单例的静态类在哪里ISessionFactory

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

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

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

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

对于温莎,我认为(我对它的 API 不是很熟悉,你可能需要调整它,但它应该给你一个想法)它会是这样的

container.Register(
    Component.For<ISession>
    .UsingFactoryMethod(
        x => x.Resolve<ISessionFactory>().OpenSession())
    .LifeStyle.Transient);

也就是说,你告诉容器,“当有人请求 ISession 时,运行这个获取ISessionFactory并打开会话的小委托,然后给他们那个ISession实例。”

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

根据我的经验,这通常意味着容器至少会泄漏到我的应用程序的“主窗体”中:当需要创建窗体时,它会创建一个新的生命周期范围/嵌套容器并显示该窗体。但是低于这个级别的东西对容器一无所知;只是在一组组件周围放一个套索,然后说“在表单关闭时摆脱所有这些”。

(这是为了防止ISession在大多数应用程序中只使用一个大喇叭。这在 ASP.NET 中运行良好,每个请求一个会话,但在 Windows 窗体中,正如您所注意到的,它就像是陈旧对象的定时炸弹例外。最好让每个“工作单元”(通常是每个表单或服务)都有自己的ISession.)

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

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

于 2010-08-21T16:30:56.203 回答
1

为什么不为每个演示者/控制器SessionProvider单独设置一个 (DAO)?Data Access Objects您的模型通过每个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;
        }
于 2010-08-19T13:25:06.350 回答