Session NHibernate ArgumentOutOfRangeException

Session NHibernate ArgumentOutOfRangeException,session,nhibernate,task,Session,Nhibernate,Task,我最近遇到了一个实例,我想从web应用程序中定期运行的任务中访问数据库。我重构了代码以使用ThreadStaticSessionContext,这样我就可以获得一个没有HttpContext的会话。这对于读取很好,但是当我尝试刷新任务的更新时,我得到“索引超出范围。必须是非负的并且小于集合的大小。”错误。通常,我看到的这个错误与在映射中两次使用列名有关,但这似乎不是问题所在,因为如果会话与请求关联,我可以更新该表(我查看了,没有看到任何重复项)。只有当任务尝试刷新时,我才会得到异常 有人知道为什

我最近遇到了一个实例,我想从web应用程序中定期运行的任务中访问数据库。我重构了代码以使用ThreadStaticSessionContext,这样我就可以获得一个没有HttpContext的会话。这对于读取很好,但是当我尝试刷新任务的更新时,我得到“索引超出范围。必须是非负的并且小于集合的大小。”错误。通常,我看到的这个错误与在映射中两次使用列名有关,但这似乎不是问题所在,因为如果会话与请求关联,我可以更新该表(我查看了,没有看到任何重复项)。只有当任务尝试刷新时,我才会得到异常

有人知道为什么它可以通过请求而不是任务调用正常工作吗

可能是因为任务是异步的吗

调用堆栈:

会话生成:

internal static ISession CurrentSession {
  get {
    if(HasSession) return Initializer.SessionFactory.GetCurrentSession();

    ISession session = Initializer.SessionFactory.OpenSession();
    session.BeginTransaction();
    CurrentSessionContext.Bind(session);
    return session;
  }
}

private static bool HasSession {
  get { return CurrentSessionContext.HasBind(Initializer.SessionFactory); }
}
要从中访问数据库的任务:

    _maid = Task.Factory.StartNew(async () => {
      while(true) {

        if(CleaningSession != null) CleaningSession(Instance, new CleaningSessionEventArgs { Session = UnitOfWorkProvider.CurrentSession });

        UnitOfWorkProvider.TransactionManager.Commit();
        await Task.Delay(AppSettings.TempPollingInterval, _paycheck.Token);
      }
      //I know this function never returns, I'm using the cancellation token for that
      // ReSharper disable once FunctionNeverReturns
    }, _paycheck.Token);

    _maid.GetAwaiter().OnCompleted(() => _maid.Dispose());
编辑:快速澄清上述某些类型。CleaningSession是一个触发事件,用于运行需要执行的各种操作,而_paycheck是该任务的CancellationTokenSource

编辑2:哦,是的,这是使用NHibernate版本4.0.0.4000

编辑3:此后,我尝试使用计时器执行此操作,结果相同

编辑4:从源代码中可以看到,它正在ILST上执行foreach循环。与foreach循环中的IndexOutOfRangeException相关的问题往往表明存在并发问题。除非我误解了ThreadStaticSessionContext的目的,否则我仍然不认为这是一个什么问题

编辑5:我认为这可能是因为请求在线程之间来回跳转,所以我尝试创建一个新的SessionContext,它结合了WebSessionContext和ThreadStaticSessionContext的逻辑。但还是有问题


编辑6:这似乎与我设置的监听器有关,该监听器用于在实体上的某些审核字段被保存之前更新它们。如果我不运行它,提交就会正常进行。通过事件而不是OnPreInsert来实现这一点会更好吗?还是改用拦截器呢?

在得过且过之后,我准确地找到了问题所在。基本上,在我的监听器中,有一个用于加载从PreUpdate事件内部调用的当前用户记录的查询


我发现了两种解决方案。我可以将用户缓存在内存中,避免查询,但可能会有过时的数据(这里除了id之外,其他什么都不重要)。或者,我可以打开一个临时的无状态会话,并使用它来查找有问题的用户

我的问题非常相似,但帮助我认识到我正在查询数据库以获取当前用户,但我应该这样做。谢谢大家!
    _maid = Task.Factory.StartNew(async () => {
      while(true) {

        if(CleaningSession != null) CleaningSession(Instance, new CleaningSessionEventArgs { Session = UnitOfWorkProvider.CurrentSession });

        UnitOfWorkProvider.TransactionManager.Commit();
        await Task.Delay(AppSettings.TempPollingInterval, _paycheck.Token);
      }
      //I know this function never returns, I'm using the cancellation token for that
      // ReSharper disable once FunctionNeverReturns
    }, _paycheck.Token);

    _maid.GetAwaiter().OnCompleted(() => _maid.Dispose());