我最近遇到了一個實例,我想從Web應用程序中定期運行的任務中找到數據庫。我重構了使用ThreadStaticSessionContext的代碼,以便我可以在沒有HttpContext的情況下獲得會話。這對於讀取工作正常,但是當我嘗試從Task中刷新更新時,我得到「索引超出範圍,必須是非負數,並且小於集合的大小。」錯誤。通常我看到的這個錯誤與在映射中使用兩個列名有關,但這似乎並不是問題,因爲如果會話與請求相關聯,我可以更新該表(我看了看,我沒有看到任何重複)。只有在任務嘗試刷新時纔會出現異常。NHibernate ArgumentOutOfRangeException
有誰知道爲什麼它可以在請求中正常工作,但不是來自任務的調用?
難道是因爲任務是異步的嗎?
調用堆棧:
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是Task的CancellationTokenSource。
編輯2:哦,是的,這就是使用NHibernate版本4.0.0.4000
編輯3:因爲我已經嘗試這種使用定時器,具有相同的結果。
編輯4:從我所看到的源代碼中,它在IList上做了一個foreach循環。與foreach循環中的IndexOutOfRangeException有關的問題傾向於暗示併發問題。除非我誤解了ThreadStaticSessionContext的目的,否則我仍然不知道這會是一個問題。
編輯5:我想這可能是因爲在線程之間彈跳的請求,所以我試圖創建一個新的SessionContext,結合了WebSessionContext和ThreadStaticSessionContext的邏輯。雖然...
編輯6:看起來這與我設置的一個監聽器有關,它們在實體保存之前更新了一些審計字段。如果我不運行它,那麼提交就會正常發生。通過一個事件而不是OnPreInsert執行此操作會更好嗎,還是使用攔截器?