2012-04-30 63 views
1

我有一個使用絕對最新版本(3.3)的Web應用程序,並且在HttpModule中使用按會話請求會話管理,所以多個會話衝突沒有問題。不幸的是,我發現在我執行一個Transaction.Commit後,會話會立即自動關閉,我只在實際執行Create,Update或Delete時纔會執行此操作。我在我的NHibernate日誌中發現這個。NHibernate Transaction.Commit自動關閉會話

我知道一個事實,我沒有這樣做,因爲唯一的ISession.Close函數調用正在我的HttpModule中完成。

是的,當然,我可以在我的SessionManager中放入代碼來檢查IsClosed參數,然後使用OpenSession函數而不是GetCurrentSession,但是這應該發生嗎?有什麼方法可以通過我的配置或我可以在Session或Transaction對象上設置的屬性來防止這種情況,或者這只是我無法在任何地方找到任何文檔的新功能之一?

請幫忙。

布賴恩

我被要求提供一些代碼,所以這裏是爲HTTP模塊的代碼:

public class NhibernateModule : IHttpModule 
{ 
    public void Dispose() 
    { 
    } 

    public void Init(HttpApplication context) 
    { 
     context.BeginRequest += new EventHandler(context_BeginRequest); 
     context.EndRequest += new EventHandler(context_EndRequest); 
    } 

    public void context_BeginRequest(Object sender, EventArgs e) 
    { 
     WebSessionContext.Bind(NhibernateSessionManager.GetContextSession()); 
    } 

    public void context_EndRequest(Object sender, EventArgs e) 
    { 
     ISession session = WebSessionContext.Unbind(NhibernateSessionManager.SessionFactory); 

     if (session != null) 
     { 
      if (session.Transaction != null && session.Transaction.IsActive) 
      { 
       session.Transaction.Rollback(); 
      } 
      else 
       session.Flush(); 

      session.Close(); 
     } 
    } 
} 

}

接下來,你會發現,我現在用的是原來的代碼在我的SessionManager中:

public sealed class NhibernateSessionManager 
{ 
    private readonly ISessionFactory sessionFactory; 
    public static ISessionFactory SessionFactory 
    { 
     get { return Instance.sessionFactory; } 
    } 

    private ISessionFactory GetSessionFactory() 
    { 
     return sessionFactory; 
    } 

    public static NhibernateSessionManager Instance 
    { 
     get { return NestedSessionManager.sessionManager; } 
    } 

    public static ISession GetContextSession() 
    { 
     ISession session; 
     if (CurrentSessionContext.HasBind(SessionFactory)) 
     { 
      session = SessionFactory.GetCurrentSession(); 
     } 
     else 
     { 
      session = SessionFactory.OpenSession(); 
      CurrentSessionContext.Bind(session); 
     } 
     return session; 
    } 

    private NhibernateSessionManager() 
    { 
     if (sessionFactory == null) 
     { 
      Configuration configuration; 
      configuration = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config")); 
      log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config"))); 

      //Configuration configuration = new Configuration().Configure(); 
      if (configuration == null) 
      { 
       throw new InvalidOperationException("NHibernate configuration is null."); 
      } 
      else 
      { 
       sessionFactory = configuration.BuildSessionFactory(); 
       if (sessionFactory == null) 
        throw new InvalidOperationException("Call to BuildSessionFactory() returned null."); 
      } 
     } 
    } 

    class NestedSessionManager 
    { 
     internal static readonly NhibernateSessionManager sessionManager = new NhibernateSessionManager(); 
    } 
} 

最後,這裏是一個函數,當前causi在Transaction.Commit()之後立即關閉會話。每個內部函數檢索當前會話,然後處理一個保存呼叫。

public static Int32 AddVideo(VideoFile Video, Int32 UserID, Int16 InstID) 
    { 
     log.Debug("Begin AddVideo"); 
     Int32 FileID = 0; 

     using (ISession Session = NhibernateSessionManager.GetContextSession()) 
     { 
      using (ITransaction Transaction = Session.BeginTransaction()) 
      { 
       Video.Created = DateTime.Now; 
       Video.Modified = DateTime.Now; 

       FileID = (Int32)Session.Save(Video); 
       Video.FileID = FileID; 

       // Need to process through all the categories and insert records into the ivxFileCategories table 
       // to associate the newly created file with the chosen categories 
       if (Video.CategoryAssociations != null) 
       { 
        log.Info("Number of categories to be associated with the video: " + Video.CategoryAssociations.Count); 
        for (int i = 0; i < Video.CategoryAssociations.Count; i++) 
        { 
         CategoryFileAssociation Assoc = (CategoryFileAssociation)Video.CategoryAssociations[i]; 
         Assoc.FileID = FileID; 
         AssociationManager.AddCategoryFileTransaction(Assoc); 
        } 
       } 

       // Need to add the default file access for the UserDetail that is creating the new video which will always 
       // be Admin because the UserDetail creating a file should always have admin access over the file, no matter 
       // what their default role is. 
       AssociationManager.AddFileAccessTransaction(FileID, UserID, UserClassConstants.IVXUSERCLASS_ADMIN); 

       // Need to add the institutional association based on whether the new video was created by a librarian 
       // or one of the iVidix admins 
       AssociationManager.AddInstitutionFileTransaction(InstID, FileID); 

       Transaction.Commit(); 
      } 
     } 

     log.Debug("End AddVideo"); 
     return FileID; 
    } 
+0

您是否使用嵌套事務?你在什麼時候打電話?提交?我們可以看到一些保存代碼和HttpModule的代碼。 – Rippo

回答

4

由於會話使用using Statement,因此會話將置於AddVideo方法中。

using (ISession Session = NhibernateSessionManager.GetContextSession()) 
{ 

} 
1

我會完全推薦遠離條帶化交易的東西

using (ISession Session = NhibernateSessionManager.GetContextSession()) 
{ 
    using (ITransaction Transaction = Session.BeginTransaction()) 
    { 
    ... 
    } 
} 

,並將其移動到開始/結束請求。這樣你的每個請求都有一個UOW for。由於using statement,您的會議正在關閉IS。

你開始然後請求代碼可以沿着線的東西: -

var session = sessionFactory.OpenSession(); 
CurrentSessionContext.Bind(session); 
session.BeginTransaction(); 

和您的最終要求: -

var session = CurrentSessionContext.Unbind(sessionFactory); 

if (session != null) 
{ 
    if (session.Transaction.IsActive) 
    { 
     try 
     { 
      session.Transaction.Commit(); 
     } 
     catch 
     { 
      session.Transaction.Rollback(); 
     } 
    } 
    session.Close(); 
} 

我有這個在我的Global.asax

public static ISessionFactory SessionFactory { get; set; } 

和這個在我的知識館裏

public ISession Session 
    { 
     get 
     { 
      return SessionFactory.GetCurrentSession(); 
     } 
    } 

現在我使用IOC將sessionFactory傳遞給我的存儲庫層,否則您需要手動將它傳遞給自己。

1

提交事務將結束該會話。

移動你的交易開始context_BeginRequest和context_EndRequest

提交/清理我其實不喜歡在視圖模式會議,並希望保持我的交易開啓儘可能短和相當注入會話到控制器。然後我在行動或服務中執行交易。我更喜歡這種細粒度的交易控制,並保持它們短暫的生命,避免任何鎖定問題。