NHibernate ISession Flush: где и когда его использовать и почему?

Одна из вещей, которая меня полностью сбивает с толку, - это использование session.Flush в сочетании с session.Commit и session.Close.

Иногда session.Close работает, например, фиксирует все необходимые мне изменения. Я знаю, что мне нужно использовать фиксацию, когда у меня есть транзакция или единица работы с несколькими созданиями / обновлениями / удалениями, чтобы я мог выбрать откат в случае возникновения ошибки.

Но иногда логика session.Flush действительно сбивает меня с толку. Я видел примеры, когда у вас есть session.SaveOrUpdate(), за которым следует флеш, но когда я удаляю флеш, он все равно работает нормально. Иногда я сталкиваюсь с ошибками в операторе Flush, в котором говорится, что время сеанса истекло, и удаление его позволило убедиться, что я не столкнулся с этой ошибкой.

Есть ли у кого-нибудь хорошие рекомендации относительно того, где и когда использовать флеш? Я проверил документацию NHibernate по этому поводу, но до сих пор не могу найти однозначного ответа.


person Jon Limjap    schedule 04.09.2008    source источник


Ответы (4)


Вкратце:

  1. Всегда используйте транзакции
  2. Не используйте Close(), вместо этого заключите свои вызовы в ISession внутри оператора using или управляйте жизненным циклом ISession в другом месте.

Из документации:

Время от времени ISession будет выполнять операторы SQL, необходимые для синхронизации состояния соединения ADO.NET с состоянием объектов, хранящихся в памяти. Этот процесс, сброс, по умолчанию происходит в следующих точках.

  • из некоторых вызовов Find() или Enumerable()
  • с NHibernate.ITransaction.Commit()
  • с ISession.Flush()

Операторы SQL выдаются в следующем порядке

  1. все вставки сущностей, в том же порядке соответствующие объекты были сохранены с использованием ISession.Save()
  2. все обновления сущностей
  3. все удаления коллекции
  4. все удаления, обновления и вставки элементов коллекции
  5. все вставки коллекции
  6. все удаления сущностей, в том же порядке соответствующие объекты были удалены с помощью ISession.Delete()

(Исключением является то, что объекты, использующие создание собственного идентификатора, вставляются при сохранении.)

За исключением случаев, когда вы явно Flush(), нет абсолютно никаких гарантий относительно того, когда Сеанс выполняет вызовы ADO.NET, только порядок, в котором они выполняются. Однако NHibernate гарантирует, что ISession.Find(..) методы никогда не вернут устаревшие данные; они также не вернут неправильные данные.

Можно изменить поведение по умолчанию, чтобы очистка выполнялась реже. Класс FlushMode определяет три разных режима: очистка только во время фиксации (и только когда используется NHibernate ITransaction API), автоматическая очистка с использованием описанной процедуры или никогда не сбрасывание, если Flush() не вызывается явно. Последний режим полезен для длительных единиц работы, когда ISession остается открытым и отключенным в течение длительного времени.

...

Также см. этот раздел:

Завершение сеанса состоит из четырех отдельных этапов:

  • очистить сессию
  • совершить транзакцию
  • закрыть сессию
  • обрабатывать исключения

Очистка сеанса

Если вы используете ITransaction API, вам не нужно беспокоиться об этом шаге. Это будет выполняться неявно при фиксации транзакции. В противном случае вы должны вызвать ISession.Flush(), чтобы убедиться, что все изменения синхронизированы с базой данных.

Фиксация транзакции базы данных

Если вы используете NHibernate ITransaction API, это выглядит так:

tx.Commit(); // flush the session and commit the transaction

Если вы сами управляете транзакциями ADO.NET, вы должны вручную Commit() транзакцию ADO.NET.

sess.Flush();
currentTransaction.Commit();

Если вы решите не фиксировать изменения:

tx.Rollback();  // rollback the transaction

or:

currentTransaction.Rollback();

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

Закрытие ISession

Вызов ISession.Close() отмечает конец сеанса. Основное значение Close () заключается в том, что соединение ADO.NET будет разорвано сеансом.

tx.Commit();
sess.Close();

sess.Flush();
currentTransaction.Commit();
sess.Close();

Если вы предоставили собственное соединение, Close() возвращает ссылку на него, поэтому вы можете вручную закрыть его или вернуть в пул. В противном случае Close() возвращает его в пул.

person Matt Hinze    schedule 04.09.2008
comment
для меня эта строка была ключевой: основное значение Close () заключается в том, что соединение ADO.NET будет отключено сеансом. если вы не вызовете ISession.Close (), ваши соединения будут заполнены до тех пор, пока вы не получите таймауты db. : o - person Dave Thieben; 12.11.2010
comment
Обычно мы: открываем сеанс session.BeginTransaction () работаем ... session.Transaction.Commit () session.BeginTransaction () работаем ... session.Transaction.Commit () session.BeginTransaction () работаем .. session.Transaction.Commit () удалить сеанс. - person Agile Jedi; 09.05.2013
comment
Блестящая запись, +1 и т. Д. - однако я думаю, что может потребоваться редактирование, потому что вы говорите вверху Никогда не используйте закрытие, а затем позже. Если вы откатываете транзакцию, вы должны немедленно закрыть и отбросить текущий сеанс - person SpaceBison; 14.04.2014
comment
Можно ли изменить порядок операторов SQL. Я имею в виду, что мне нужно выполнить обновление объекта сущности, а затем вставить, потому что у меня есть ограничение в соответствующей таблице. - person bob_saginowski; 25.04.2017

Начиная с NHibernate 2.0, транзакции необходимы для операций с БД. Следовательно, вызов ITransaction.Commit() будет обрабатывать любую необходимую промывку. Если по какой-то причине вы не используете транзакции NHibernate, то автоматической очистки сеанса не будет.

person Sean Carpenter    schedule 04.09.2008

Время от времени ISession будет выполнять операторы SQL, необходимые для синхронизации состояния соединения ADO.NET с состоянием объектов, хранящихся в памяти.

И всегда используйте

 using (var transaction = session.BeginTransaction())
 {
     transaction.Commit();
 }

после того, как изменения зафиксированы, чем эти изменения для сохранения в базе данных, мы используем transaction.Commit ();

person Community    schedule 05.03.2014

Вот два примера моего кода, в котором он потерпит неудачу без session.Flush ():

http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html

в конце вы можете увидеть раздел кода, в котором я включил вставку идентификатора, сохранил объект, затем очистил его, а затем отключил вставку идентификатора. Без этого сброса казалось, что вставка идентификатора включается и выключается, а затем сохраняется сущность.

Использование Flush () дало мне больше контроля над происходящим.

Вот еще один пример:

Отправка сообщения NServiceBus внутри TransactionScope

Я не совсем понимаю, почему именно здесь, но Flush () предотвратил мою ошибку.

person Paul T Davies    schedule 06.11.2012