NHibernate ISession Flush: где и когда его использовать и почему? - PullRequest
185 голосов
/ 04 сентября 2008

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

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

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

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

Ответы [ 4 ]

233 голосов
/ 04 сентября 2008

Коротко:

  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(), нет абсолютно никаких гарантий относительно того, когда Session выполняет вызовы ADO.NET, только порядок, в котором они выполняются . Однако NHibernate гарантирует, что методы ISession.Find(..) никогда не будут возвращать устаревшие данные; и при этом они не будут возвращать неправильные данные.

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

...

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

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

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

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

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

Подтверждение транзакции базы данных

Если вы используете API-интерфейс NHibernate ITransaction, это выглядит следующим образом:

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

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

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

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

tx.Rollback();  // rollback the transaction

или

currentTransaction.Rollback();

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

Закрытие ISession

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

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

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

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

14 голосов
/ 04 сентября 2008

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

1 голос
/ 05 марта 2014

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

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

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

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

0 голосов
/ 06 ноября 2012

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

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

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

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

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

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

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

...