NHibernate, как избежать закрытия сессии

Я не могу понять, почему я закрываю сеанс при вызове второго запроса в моем классе.

Сначала я вызываю метод, getPoliceData() работает нормально. После этого я вызываю GetSkadeData(), и он выдает ошибку:

класс DbFactory выглядит так

class DbFactory
{
    private static Lazy<ISessionFactory> factory = new Lazy<ISessionFactory>(GetSessionFactory, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);

    public DbFactory()
    {



    }
    public List<PoliceData> getPoliceData()  {
    using (ISession session = OpenSession())
        {
            IList<PoliceData> pols = session.Query<PoliceData>().Where(p => p.policyNumber == 053126703).ToList();

         return pols.ToList();
        }

    }

    public List<SkadeData> getSkadeData()
    {
        using (ISession session = OpenSession())
        {
            IList<SkadeData> skader = session.Query<SkadeData>().Where(p => p.Postnr == "7700").ToList();

            return skader.ToList();
        }

    }



    private static ISession OpenSession()
    {
        return factory.Value.GetCurrentSession();
    }

    private static ISessionFactory GetSessionFactory()
    {
        //NHibernate.Cfg.Configuration
        var c = new Configuration();
        //c.Configure();
        c.DataBaseIntegration(db =>
        {
            db.ConnectionString = "Server=\"localhost\";database=testdb;Integrated Security=SSPI";
            db.Dialect<NHibernate.Dialect.MsSql2012Dialect>();

        });
        //c.Configure("c:\XML.xml");

        ModelMapper maps = new ModelMapper();
        maps.AddMapping<PoliceDataMap>();
        maps.AddMapping<SkadeDataMap>();
        c.AddMapping(maps.CompileMappingForAllExplicitlyAddedEntities());
        c.CurrentSessionContext<NHibernate.Context.ThreadLocalSessionContext>();
        //c.Configure().Configure();
        var sessionFac = c.BuildSessionFactory();
        return sessionFac;

        //return sessionFac.GetCurrentSession();

    }

}

Когда я вызываю метод из другого класса, я делаю это

List<PoliceData> test = new List<PoliceData>();
List<SkadeData> skader = new List<SkadeData>();
DbFactory poli = new DbFactory();
test = poli.getPoliceData();
skader = poli.getSkadeData();

Нужно ли мне создавать новый экземпляр dbfactory или можно использовать один и тот же сеанс для двух разных запросов. Было бы неплохо, если бы Nhibernate был настроен только один раз, и после этого вы просто открывали и закрывали сеанс, когда это необходимо.


person havmaage    schedule 18.10.2015    source источник


Ответы (2)


В целом (с любым инструментом ORM) нам следует избегать оператора using(OpenSession()) {...} и держать сеанс открытым не только для одной операции, но и для полного веб-запроса или единицы работы. Проверьте документ:

2.3. Контекстные сеансы

Большинству приложений, использующих NHibernate, нужны те или иные формы контекстных сеансов, где данный сеанс действует во всем объеме данного контекста. Однако в разных приложениях определение того, что представляет собой контекст, обычно отличается; и разные контексты определяют разные рамки понятия тока.

...

См. документацию API для интерфейса NHibernate.Context.ICurrentSessionContext для подробного обсуждения его контракта. Он определяет единственный метод CurrentSession(), с помощью которого реализация отвечает за отслеживание текущего контекстного сеанса. По умолчанию NHibernate поставляется с несколькими реализациями этого интерфейса:

  • NHibernate.Context.CallSessionContext — текущие сессии отслеживаются CallContext. Вы несете ответственность за привязку и отвязку экземпляра ISession с помощью статических методов класса CurrentSessionContext .

  • NHibernate.Context.ThreadStaticSessionContext — текущий сеанс хранится в статической переменной потока. Этот контекст поддерживает только одну фабрику сеансов. Вы несете ответственность за привязку и отвязку экземпляра ISession с помощью статических методов класса CurrentSessionContext.

  • NHibernate.Context.WebSessionContext — сохраняет текущую сессию в HttpContext. Вы несете ответственность за привязку и отвязку экземпляра ISession с помощью статических методов класса CurrentSessionContext.

  • NHibernate.Context.WcfOperationSessionContext — текущие сеансы отслеживаются WCF OperationContext. Вам необходимо зарегистрировать расширение WcfStateExtension в WCF. Вы несете ответственность за привязку и отвязку экземпляра ISession с помощью статических методов класса CurrentSessionContext.

  • NHibernate.Context.ManagedWebSessionContext — текущие сеансы отслеживаются HttpContext. Удалено в NHibernate 4.0 — вместо него следует использовать NHibernate.Context.WebSessionContext. Вы несете ответственность за привязку и отвязку экземпляра ISession со статическими методами этого класса, он никогда не открывает, не очищает и не закрывает сам ISession.

person Radim Köhler    schedule 18.10.2015
comment
Пока мы этим занимаемся, я настоятельно не рекомендую открывать ISession для всего HTTP-запроса. Если вы используете ASP.NET MVC, откройте сеанс в методе действия (или ранее, если ваши фильтры действий или что-то еще не требуют доступа к БД) и закройте, как только метод действия завершится. Таким образом, вас не будут кусать ленивые загрузки, выборки N+1 и другие неприятные вещи. Считайте из БД, подготовьте модели представления, закройте ISession и только потом визуализируйте представление. - person Anton Gogolev; 18.10.2015

Вы пытались создать ISession с помощью factory.value.OpenSession()?

Если вы хотите поделиться ISession на основе своего примера кода, вы можете изменить свой метод, чтобы использовать ISession, а затем вызвать его следующим образом:

DbFactory poli = new DbFactory();
using (ISession session = poli.OpenSession()) {
  test = poli.getPoliceData(session);
  skader = poli.getSkadeData(session);
}

и ваш метод теперь станет:

public List<SkadeData> getSkadeData(ISession session)
{
  IList<SkadeData> skader = session.Query<SkadeData>().Where(p => p.Postnr == "7700").ToList();

  return skader.ToList();
}

Это может сработать!

person c.sokun    schedule 18.10.2015
comment
Привет, ребята, большое спасибо, я посмотрю на это, как только я вернусь домой с моей повседневной работы сегодня. Спасибо за ответы - person havmaage; 19.10.2015