NHibernate ArgumentOutOfRangeException

时间:2014-10-20 18:20:34

标签: session nhibernate task

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

有谁知道为什么它会在请求中正常工作,而不是来自任务的调用?

可能是因为Task是异步的吗?

调用堆栈:

at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.System.Collections.IList.get_Item(Int32 index)
at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
at NHibernate.Engine.ActionQueue.ExecuteActions()
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()

会话生成:

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 :从我所看到的来源,它正在对IList进行foreach循环。有关foreach循环中的IndexOutOfRangeException的问题倾向于提出并发问题。除非我误解了ThreadStaticSessionContext的用途,否则我仍然看不出这是一个什么问题。

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

编辑6 :这似乎与我设置的侦听器有关,这些侦听器在保存之前更新实体上的某些审核字段。如果我不运行它,则提交正确。通过一个事件而不是OnPreInsert,或者使用拦截器代替它会更好吗?

1 个答案:

答案 0 :(得分:0)

经过混乱之后,我发现了问题的确切位置。基本上,有一个查询被运行以加载从我的监听器中的PreUpdate事件内部调用的当前用户记录。

我遇到了两个解决方案。我可以将用户缓存在内存中,避免查询,但可能有过时的数据(除此之外的任何内容都不重要)。或者,我可以打开一个临时的无状态会话,并使用它来查找有问题的用户。