Hi everybody,
I have been working with NHibernate for a while now. I am using NHibernateSessionManager class from the SharpArchitecture(
http://code.google.com/p/sharp-architecture/) to manage my application sessions. The application I am developing is a Winform application using MDI container/childs.
The issue I came accross recently is that I have a background process which update the user information and check its inbox messages. I can't manage a single session in my application anymore for the following reasons :
1) The background process needs to flush/commit user data (every 2 minutes)
2) While the background process runs, the user can update other business related data
3) As there is only one session per application lifecycle, when the background process flushes/commits, it also commits data that have been temporarily saved but not yet committed (because the user hasn't hit Save button).
Therefore I decided to use one session per MDI form. Each form inherits from the following BaseForm :
Code:
public class BaseForm : Form
{
public BaseForm()
{
}
public ISession Session
{
get
{
//return (ISession)CustomContainer.WindsorContainer[typeof(ISession)];
return NHibernateSession.GetSession(this.Name);
}
}
public IDaoFactory DaoFactory
{
get
{
//return (IDaoFactory)CustomContainer.WindsorContainer[typeof(IDaoFactory)];
return (IDaoFactory)(new NHibernateDaoFactory(this.Name));
}
}
}
I am using the form name to identify the session but it could be anything else.
Here is the NhibernateSession manager I have modified in order to use a single session per form.
Code:
public interface ISessionStorage
{
IDictionary<string,ISession> Sessions { get;}
}
public static class NHibernateSession
{
public static Configuration Init(ISessionStorage storage, string cfgFile)
{
Check.Require(storage != null, "storage mechanism was null but must be provided");
Configuration cfg = ConfigureNHibernate(cfgFile);
SessionFactory = cfg.BuildSessionFactory();
Storage = storage;
return cfg;
}
public static ISessionFactory SessionFactory { get; set; }
public static ISessionStorage Storage { get; set; }
public static ISession GetSession(string sessionName)
{
if (!Storage.Sessions.ContainsKey(sessionName))
Storage.Sessions[sessionName] = SessionFactory.OpenSession();
return Storage.Sessions[sessionName];
}
public static void CloseSession(string sessionName)
{
if (Storage.Sessions.ContainsKey(sessionName))
{
Storage.Sessions[sessionName].Close();
Storage.Sessions.Remove(sessionName);
}
}
private static Configuration ConfigureNHibernate(string cfgFile)
{
Configuration cfg = new Configuration();
if (string.IsNullOrEmpty(cfgFile))
return cfg.Configure();
return cfg.Configure(cfgFile);
}
}
Here is the implementation of my DaoFactory
Code:
public class NHibernateDaoFactory : IDaoFactory
{
public NHibernateDaoFactory(string sessionName)
{
Check.Require(sessionName != null, "Session may not be null");
Session = sessionName;
}
protected string Session { get; set; }
public IClientDao GetClientDao()
{
return new ClientDao(Session);
}
public IUserDao GetUserDao()
{
return new UserDao(Session);
}
}
I have some questions regarding this architecture :
1) Is it bad design to have one instance of my DaoFactory per MDI form to handle multiple sessions ? Before I was sharing one single instance of IDaoFactory throughout the application lifecycle thanks to Windsor Castle. Now, with this new design, I have to create a new instance for each MDI form I open and send the session name into it so that I am sure all DAOs used in my form controllers are using the same session.
2) Is there a better way to maintain sessions ? Is it bad design to let your DAOs know about sessions ?
Thank you in advance for your advices. Much appreciated.