代码之家  ›  专栏  ›  技术社区  ›  Dave Thieben

用ninject在生成的线程中确定nhibernate isession的作用域

  •  2
  • Dave Thieben  · 技术社区  · 16 年前

    好的,这里是场景。我有一个ASP.NET站点,它周期性地生成一个后台线程来做一些工作。线程的执行由一个JobRunner组成,它遍历一个Ijobs列表,并对每个Ijobs调用execute()。JobRunner和每个iJob都由Ninject创建。一些iJobs依赖于iRepository<ModelType>。我使用的IRepository的实现是针对nhibernate的,因此它有一个isession的构造函数参数。到目前为止,我已经让ninject从一个isessionfactory返回一个isession,其范围是每个请求(inRequestScope)。

    问题是:当各种Ijobs进行处理(包括保存到iRepository)时,数据永远不会持久化,因为从未调用isession.flush()。每个iJob都不知道它使用的iRepository的实现。同样,JobRunner对它正在运行的iJobs的实现也一无所知。对于Web应用程序的其余部分,它工作得很好,因为ISession.flush()在应用程序_EndRequest中被调用。

    我尝试将ISession作为jobRunner的构造函数参数,以便在所有Ijobs完成处理后可以对其调用flush(),但它似乎获得的ISession与Ijobs不同(调用session.gethashcode()为jobRunner返回不同的值,但对于所有Ijobs返回的值相同)。我将ninject配置为基于httpcontext的scope isession(如果有),否则使用currentThread。我认为,由于JobRunner在一个单独的线程上,它将得到一个IsSession,其作用域是CurrentThread,并且由于所有Ijobs都与JobRunner在同一线程上运行,所以它们都应该得到相同的IsSession,但它们不是。

    所以我的问题是,有没有更好的方法来做我想做的?有人知道为什么我会为同一线程上的不同请求获得不同的isession实例吗?

    现在我有一个解决方法——我把session.flush()作为nhibernaterepository.save()方法的最后一行,但我对此并不满意。

    1 回复  |  直到 16 年前
        1
  •  1
  •   Dave Thieben    16 年前

    我找到了解决办法。我的jobRunner对象正在global.asax的应用程序启动方法中实例化,因此保留了该线程ID而不是后台线程ID。

    我创建了一个包装类,它采用一个类型并使用ninject创建一个实例,每次后台线程开始处理时,它都使用包装类来获取JobRunner的实例。它在适当的线程上创建,这样我就可以获得与iRepository相同的ISession,以便在所有iJobs完成后调用session.flush()。

    也许有一个更优雅的解决方案,但在那之前,这是很有效的。

    推荐文章