使用NHibernate的Windows服务中的多个SessionFactories

Rob*_*lor 6 .net nhibernate service session

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

我现在必须创建一个Windows服务,它将使用相同的业务逻辑/数据访问DLL.但是,当我尝试在服务应用程序中引用2个会话工厂并调用factory.GetCurrentSession()方法时,我收到错误消息"没有会话绑定到当前上下文".

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

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();
    }
}  
Run Code Online (Sandbox Code Playgroud)

配置文件具有以下设置:

<property name="current_session_context_class">call</property>
Run Code Online (Sandbox Code Playgroud)

该服务设立工厂:

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);
Run Code Online (Sandbox Code Playgroud)

最后,我尝试通过以下方式调用正确的工厂:

ISession session = StaticSessionManager.SessionFactory.GetCurrentSession();
Run Code Online (Sandbox Code Playgroud)

谁能建议一个更好的方法来处理这个?
提前致谢!

Wil*_*ler 4

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

编辑#1

您会建议我在需要时创建会话,还是将它们保持打开状态?

APIISession在内部处理其连接。一段时间后,如果没有请求与底层数据库进行交互,则连接将关闭,但您ISession会保留其连接实例。一旦需要与数据库执行一些其他事务,它就会重新打开以前使用的连接。

要回答您的问题,首选方法是ISession每页(Web)或每表单(桌面)一个 API 实例。例如,假设您有一个会计软件,并且用户需要对客户进行一些管理。然后,当您CustomerMgmtForm加载时,您应该提供一个实例,ISession以便它可以加载您的客户,跟踪您的更改、删除和创建的新客户(一旦加入到ISession,这样当您调用该SaveOrUpdate()方法时,它就ISession知道它必须做什么处理跟踪的更改和瞬态实体。

您想知道为什么每个页面或每个表单都有一个实例吗?

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

除此之外,当您打开 CustomerMgmtForm 时您将必须管理Customer实体。一旦您关闭了表单,甚至打开了SuppliersMgmtForm (您可以在其中管理您的供应商),您就更有可能不必跟踪您的客户。通过这样做,您将拥有该ISessionAPI 的两个实例:第一个 - customerMgmtSession,另一个 - suppliersMgmtSession。因此,它们永远不应该变得太大而导致内存泄漏,因为它们都有自己的实体需要处理或照顾。两者完全独立。

按照这种方法,您应该在 Windows 窗体的FormClosing事件或 Web 中的任何等效事件ISession上关闭并处置 API实例。因此,现在,在 Windows 服务中,您需要根据您的服务的用途来决定什么是理想情况并决定最适合您的需求。

但有一件事是,如果您的服务不需要保留任何对您的更改或实体的任何跟踪,那么 APIIStatelessSession可能更适合使用。使用它,那么我肯定建议您仅在需要与底层数据库交互时才打开或实例化无状态会话,因为保持活动状态是没有用的IStatelessSession,因为它不提供资源来保持任何状态。跟踪对您的实体执行的更改。ISession如果我没记错的话,这是和API之间的主要区别,也许也是唯一区别IStatelessSession

编辑#2

这样做,正如我在编辑 #1中提到的那样,也可能帮助您解决问题,因为您不需要调用ISessionFactory.GetCurrentSession().

我希望这有帮助!=)