2012-04-30 3 views
1

У меня есть веб-приложение, использующее абсолютную последнюю версию (3.3), и использует управление сеансом по запросу в HttpModule, поэтому нет проблем с несколькими конфликтами сеанса. К сожалению, я обнаружил, что сеанс автоматически закрывается сразу после выполнения Transaction.Commit, который я делаю только тогда, когда на самом деле выполняю Create, Update или Delete. Я нахожу это в своем журнале NHibernate.NHibernate Transaction.Commit автоматически закрывает сеанс

Я знаю, что я этого не делаю, потому что единственный вызов функции ISession.Close выполняется в моем HttpModule.

Да, конечно, я могу поместить код в свой SessionManager, чтобы проверить параметр IsClosed, а затем использовать функцию OpenSession вместо GetCurrentSession, но должно ли это даже происходить? Есть ли способ предотвратить это либо через мою конфигурацию, либо какой-либо атрибут, который я мог бы установить на объект Session или Transaction, или это только одна из новых функций, которые я не могу найти нигде в документации?

Пожалуйста, помогите.

Brian

меня попросили предоставить некоторый код, так вот код HttpModule:

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(); 
    } 
} 

Последнее, вот функция, которая в настоящее время является причиной чтобы сеанс закрылся сразу после транзакции. Commit(). Каждая из внутренних функций извлекает текущий сеанс, а затем обрабатывает вызов Save.

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

Сессия путем расположена в методе AddVideo, потому что вы используете using Statement сессии.

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

} 
1

Я полностью рекомендую удаляющей прочь транзакции вещи

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

и переместить его в конец запроса начать /. Таким образом, у каждого запроса есть UOW for. Причина, по которой ваша сессия закрывает IS из-за using statement.

Ваш начать запрос кода может затем быть что-то вдоль линий: -

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

Committing transaction завершает эту сессию.

Перемещение вашей транзакции начинают context_BeginRequest и фиксации/очистки в context_EndRequest

Я на самом деле не нравится сессию в вид рисунка и предпочитают держать свои операции открытыми как можно более коротким и довольно впрыснуть сеанс в контроллер. Затем я выполняю транзакцию в действии или услуге. Я предпочитаю этот мелкозернистый контроль транзакций и недолговечно избегает любых проблем с блокировкой.

Смежные вопросы