NHibernate и нечетная “Сессия Закрываются!” ошибки

Примечание: Теперь, когда я вывел это, я должен принести извинения за супер долгий вопрос, однако, я думаю, все нормы и информация, представленная здесь, являются в некотором роде соответствующими.


Хорошо, я добираюсь, нечетный "Сеанс Закрыт" ошибки, наугад точки в моем приложении веб-форм ASP.NET. Сегодня, однако, это наконец происходит в том же месте много раз. Я почти уверен, что ничто не располагает или закрыло сеанс в моем коде как биты кода, что использование хорошо содержится далеко от всего другого кода, как Вы будете видеть ниже.

Я также использую ninject в качестве своего МОК, который может / может не быть важным.

Хорошо, таким образом, Сначала мой SessionFactoryProvider и SessionProvider классы:


SessionFactoryProvider

public class SessionFactoryProvider : IDisposable
{
    ISessionFactory sessionFactory;

    public ISessionFactory GetSessionFactory()
    {
        if (sessionFactory == null)
            sessionFactory =
                Fluently.Configure()
                        .Database(
                            MsSqlConfiguration.MsSql2005.ConnectionString(p =>
                                p.FromConnectionStringWithKey("QoiSqlConnection")))
                        .Mappings(m =>
                            m.FluentMappings.AddFromAssemblyOf<JobMapping>())
                        .BuildSessionFactory();

        return sessionFactory;
    }

    public void Dispose()
    {
        if (sessionFactory != null)
            sessionFactory.Dispose();
    }
}

SessionProvider

public class SessionProvider : IDisposable
{
    ISessionFactory sessionFactory;
    ISession session;

    public SessionProvider(SessionFactoryProvider sessionFactoryProvider)
    {
        this.sessionFactory = sessionFactoryProvider.GetSessionFactory();
    }

    public ISession GetCurrentSession()
    {
        if (session == null)
            session = sessionFactory.OpenSession();

        return session;
    }

    public void Dispose()
    {
        if (session != null)
        {
            session.Dispose();                
        }
    }
}

Эти два класса обеспечены электричеством с помощью Ninject как так:

NHibernateModule

public class NHibernateModule : StandardModule
{        
    public override void Load()
    {
        Bind<SessionFactoryProvider>().ToSelf().Using<SingletonBehavior>();
        Bind<SessionProvider>().ToSelf().Using<OnePerRequestBehavior>();
    }
}

и насколько я могу сказать работу как ожидалось.

Теперь мой BaseDao<T> класс:


BaseDao

public class BaseDao<T> : IDao<T> where T : EntityBase
{
    private SessionProvider sessionManager;
    protected ISession session { get { return sessionManager.GetCurrentSession(); } }

    public BaseDao(SessionProvider sessionManager)
    {
        this.sessionManager = sessionManager;
    }        

    public T GetBy(int id)
    {
        return session.Get<T>(id);
    }

    public void Save(T item)        
    {
        using (var transaction = session.BeginTransaction())
        {
            session.SaveOrUpdate(item);

            transaction.Commit();
        }
    }

    public void Delete(T item)
    {
        using (var transaction = session.BeginTransaction())
        {
            session.Delete(item);

            transaction.Commit();
        }
    }

    public IList<T> GetAll()
    {
        return session.CreateCriteria<T>().List<T>();
    }

    public IQueryable<T> Query()
    {
        return session.Linq<T>();
    }        
}

Который связывается в Ninject как так:


DaoModule

public class DaoModule : StandardModule
{
    public override void Load()
    {
        Bind(typeof(IDao<>)).To(typeof(BaseDao<>))
                            .Using<OnePerRequestBehavior>();
    }
}

Теперь веб-запрос, который вызывает это, состоит в том, когда я сохраняю объект, он не произошел, пока я не внес некоторые образцовые изменения сегодня, однако изменения в моей модели не изменили код доступа к данным в так или иначе. Хотя это изменило несколько отображений NHibernate (я могу отправить их также, если кому-либо интересно),

От того насколько я могу сказать, BaseDao<SomeClass>.Get назван затем BaseDao<SomeOtherClass>.Get назван затем BaseDao<TypeImTryingToSave>.Save назван.

это является третьим, заходят в строку в Save()

using (var transaction = session.BeginTransaction())

это перестало работать с "Сессией, Закрывается!" или скорее исключение:

Session is closed!
Object name: 'ISession'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.ObjectDisposedException: Session is closed!
Object name: 'ISession'.

И действительно выполнение на Отладчике показывает в третий раз, когда сессию требуют от SessionProvider это действительно закрыто и не соединено.

Я проверил это Dispose на моем SessionFactoryProvider и на моем SessionProvider названы в конце запроса и не перед Save вызов выполняется на моем Дао.

Таким образом, теперь я немного застреваю. Несколько вещей появляются для возражения.

  • Я делаю что-нибудь, очевидно, неправильно?
  • NHibernate когда-либо закрыл сеансы без меня спрашивающий к?
  • Какие-либо обходные решения или идеи о том, что я мог бы сделать?

Заранее спасибо

18
задан Sekhat 3 April 2010 в 17:21
поделиться

2 ответа

ASP.NET - это многопоточность, поэтому доступ к ISession должен быть потокобезопасным. Предполагая, что вы используете сеанс на запрос, самый простой способ сделать это - использовать встроенную в NHibernate обработку контекстных сеансов .

Сначала настройте NHibernate для использования класса контекста веб-сеанса:

sessionFactory = Fluently.Configure()
    .Database(
        MsSqlConfiguration.MsSql2005.ConnectionString(p =>
            p.FromConnectionStringWithKey("QoiSqlConnection")))
    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<JobMapping>())
    .ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web")
    .BuildSessionFactory();

Затем используйте ISessionFactory.GetCurrentSession () , чтобы получить существующий сеанс, или привязать новый сеанс к фабрике, если таковой не существует. Ниже я собираюсь вырезать + вставить свой код для открытия и закрытия сеанса.

    public ISession GetContextSession()
    {
        var factory = GetFactory(); // GetFactory returns an ISessionFactory in my helper class
        ISession session;
        if (CurrentSessionContext.HasBind(factory))
        {
            session = factory.GetCurrentSession();
        }
        else
        {
            session = factory.OpenSession();
            CurrentSessionContext.Bind(session);
        }
        return session;
    }

    public void EndContextSession()
    {
        var factory = GetFactory();
        var session = CurrentSessionContext.Unbind(factory);
        if (session != null && session.IsOpen)
        {
            try
            {
                if (session.Transaction != null && session.Transaction.IsActive)
                {
                    session.Transaction.Rollback();
                    throw new Exception("Rolling back uncommited NHibernate transaction.");
                }
                session.Flush();
            }
            catch (Exception ex)
            {
                log.Error("SessionKey.EndContextSession", ex);
                throw;
            }
            finally
            {
                session.Close();
                session.Dispose();
            }
        }
    }        
19
ответ дан 30 November 2019 в 08:10
поделиться

Предлагаю вам установить точку останова на SessionImpl.Close / SessionImpl.Dispose и посмотрите, кто его вызывает, через трассировку стека. Вы также можете просто создать отладочную версию NH для себя и сделать то же самое.

3
ответ дан 30 November 2019 в 08:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: