我有一个Webapp,它连接到2个DB(一个核心,另一个是日志记录DB)。

现在,我必须创建一个Windows服务,该服务将使用相同的业务逻辑/数据访问DLL。但是,当我尝试在Service App中引用2个 session 工厂并调用factory.GetCurrentSession()方法时,出现错误消息“没有 session 绑定(bind)到当前上下文”。

有人对如何做到这一点有建议吗?

public class StaticSessionManager
{
    public static readonly ISessionFactory SessionFactory;
    public static readonly ISessionFactory LoggingSessionFactory;

    static StaticSessionManager()
    {
         string fileName = System.Configuration.ConfigurationSettings.AppSettings["DefaultNHihbernateConfigFile"];
         string executingPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
         fileName = executingPath + "\\" + fileName;
         SessionFactory = cfg.Configure(fileName).BuildSessionFactory();

         cfg = new Configuration();
         fileName = System.Configuration.ConfigurationSettings.AppSettings["LoggingNHihbernateConfigFile"];
         fileName = executingPath + "\\" + fileName;
         LoggingSessionFactory = cfg.Configure(fileName).BuildSessionFactory();
    }
}

配置文件具有以下设置:
<property name="current_session_context_class">call</property>

服务设置工厂:
private ISession _session = null;
private ISession _loggingSession = null;
private ISessionFactory _sessionFactory = StaticSessionManager.SessionFactory;
private ISessionFactory _loggingSessionFactory = StaticSessionManager.LoggingSessionFactory;

...

_sessionFactory = StaticSessionManager.SessionFactory;
_loggingSessionFactory = StaticSessionManager.LoggingSessionFactory;

_session = _sessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(_session);
_loggingSession = _loggingSessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(_loggingSession);

因此,最后,我尝试通过以下方式调用正确的工厂:
ISession session = StaticSessionManager.SessionFactory.GetCurrentSession();

谁能建议一个更好的方法来解决这个问题?
提前致谢!

最佳答案

我可以建议的第一件事是将两个ISessionFactory实例都设置为静态。这些应该是单例,因为它们的实例化非常昂贵。

编辑#1


ISession API在内部处理其连接。过一会儿,如果您的ISession保留其连接实例,则如果不要求与基础数据库进行交互,则该连接将关闭。一旦需要对数据库执行其他一些事务,则它将重新打开以前使用的连接。

为了回答您的问题,首选的方法是每个页面(Web)或每个表单(Desktop)的ISession API实例。例如,让我们考虑您有一个会计软件,并且用户对客户有一定的管理权。然后,当您加载CustomerMgmtForm时,您应该提供ISession实例,以便它可以加载您的客户,跟踪您的更改,删除和创建的新客户(一旦加入ISession,以便调用SaveOrUpdate()方法时,ISession知道它与跟踪的更改和临时实体有什么关系。



由于ISession API跟踪对象发生的所有更改,因此请想象一下,一旦加载了客户,供应商和其他一些实体,您就必须在应用程序中保重。对客户执行的每项更改,他们都没有对供应商的权利。但是这些客户仍然会在那里,因为这是您为客户使用的ISession的实例!然后,您的应用程序对内存的要求会随着所加载对象的数量而增长。此外,一个已知的问题是,当ISession的内存过大时,可能会导致一些内存泄漏,然后被NHibernate视为不再有效的 session ,将所有未保存的更改和所有内容都作为跟踪您的实体的 session 进行废弃现在无效。

除此之外,假设您打开CustomerMgmtForm,则必须管理Customer实体。一旦您关闭表格,甚至打开了SuppliersMgmtForm,您就更有可能不必跟踪客户,您可以在其中管理供应商。这样,您将拥有ISession API的两个实例:第一个是customerMgmtSession,另一个是suppliersMgmtSession。因此,它们都不应太大而不会引起内存泄漏,因为它们都有自己的实体来处理或保重。两者彼此完全独立。

按照这种方法,您应该在Windows Forms或Web上任何等效的FormClosing事件上关闭并处置ISession API实例。因此,现在,在Windows服务中,您可以根据服务的工作来决定理想的情况,并确定最适合您的需求的位置。

但是有一件事,如果您的服务不需要保留任何更改或实体上的任何痕迹,那么IStatelessSession API可能更适合使用。使用它,那么我可以肯定地建议您仅在需要与基础数据库进行交互时才打开或实例化无状态 session ,因为IStatelessSession不能保持事件状态,因为它没有提供保持资源的功能。有关在实体上执行的更改的任何跟踪信息。如果我没有记错的话,这是主要的,也许仅仅是(可能)ISessionIStatelessSession API之间的区别。

编辑#2

就像我在 EDIT#1 中提到的那样,这样做可能还会帮助您解决问题,因为您无需调用ISessionFactory.GetCurrentSession()

我希望这有帮助! =)

关于.net - 带有NHibernate的Windows Service中的多个SessionFactories,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2931036/

10-09 04:38