Nhibernate,WinForms,Castle Windsor:会话管理

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

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

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

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

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

NHibernateContext是我唯一的静态类,它配置NHibernate并保存在ISessionFactory单例中。

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

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

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

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

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

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

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

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

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

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

您也可以设计您的存储库,以便每个方法都需要传入一个ISession ,但这看起来好像很乏味。

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

为什么不为每个演示者/控制器安装一个带有单独Data Access Objects (DAO)的SessionProvider ? 您的模型通过每个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; ///  /// Initializes the  class. ///  static SessionProvider() { } ///  /// Gets the session. ///  /// The session. 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(); ///  /// Gets the thread-safe instance ///  /// The instance. public static OrderDataControl Instance { get { lock (lockOrderDataControl) { if (orderDataControl == null) orderDataControl = new OrderDataControl(); } return orderDataControl; } } ///  /// Gets the session. ///  /// The session. private ISession Session { get { return SessionProvider.Session; } } ///  /// Saves the specified contact. ///  /// The contact. ///  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; }