Nhibernate, WinForms, Castle Windsor: Session Management

I know that the issue of session management was raised in the past, but I could not find anything that would help me overcome my problem.

I have several repository classes (e.g. CustomerRepository, ProductRepository, etc.) that I enable through Castle Windsor (Note: I'm trying to apply a three-call pattern as indicated here ). I believe that it is best to have a session on the presenter (in my case, this is equivalent to one for each form), however, the repository classes must access the session for the current active form. I'm not sure how I incorporate this with the fact that these repositories are resolved using windsor, as the speakers are not single.

For instance:

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

Repositories need access to the session ... How do I do this with Windsor? Am I forced to manually set up a session in repositories through a property or is there a Windsor smart trick that I am not familiar with?

+2
source share
2 answers

Why not just embed ISession in your repositories instead of ISessionFactory ?

Here is the similar code that I use with Autofac, another IoC container:

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

where NHibernateContext is my one and only static class that configures NHibernate and holds on to the ISessionFactory ISessionFactory .

So my repository / search object is requesting a session:

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

Then my presenter / view model / supervisory controller / whatever Heck-We're-Call-It-This-Month just gets a repository or search object:

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

For Windsor, I think (I am not very familiar with its API, you may have to configure it, but it should give you an idea), it will be something like

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

That is, you tell the container: "When someone asks for ISession, run this little delegate, which receives an ISessionFactory and opens a session, then give them an instance of ISession .

But who closes the ISession ? It is up to you: you could have the repository explicitly close ISession in your own Dispose() method. Or you can rely on your container for closure and disposal; in Autofac, I do this with ILifetimeScope and InstancePerLifetimeScope() ; in Windsor, I believe you need to look for nested containers, so when you install a child container, all the components that it created are also located.

In my experience, this usually means that the container seeps into at least the β€œmain form” of my application: when it's time to create the form, it creates a new container / nested container lifetime and shows the form. But nothing below this level knows about the container; it's just throwing a lasso around a set of components and saying "get rid of all these cases when the form is closed."

(This is to prevent the use of just one big ISession beep on most applications. This works well in ASP.NET, one session per request, but in Windows Forms, as you noticed, it looks like a ticking time bomb for exceptions of obsolete objects. It is better for each "unit of work" (usually for each form or service) to have its own ISession .)

You can also create your repositories in such a way that each method requires passing ISession , but it seems like it is tedious.

Hope this gives you some ideas. Good luck

+4
source

Why not just one SessionProvider with individual Data Access Objects (DAO) for each master / controller? Your model is accessed through each 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; } 
+1
source

Source: https://habr.com/ru/post/1389687/


All Articles