2014-10-20 46 views
1

我最近遇到了一個實例,我想從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執行此操作會更好嗎,還是使用攔截器?

回答

0

混淆後,我發現確切的問題出在哪裏。基本上,有一個查詢被運行來加載我的偵聽器中的PreUpdate事件內部調用的當前用戶記錄。

我遇到了兩個解決方案。我可以將用戶緩存在內存中,避免查詢,但可能有陳舊的數據(除了id以外的任何其他內容)。或者,我可以打開臨時無狀態會話並使用它來查找有問題的用戶。

相關問題