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

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

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

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

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

Ответ 1

Коротко:

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

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

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

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

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

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

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

За исключением случаев, когда вы объясняете Flush(), нет никаких гарантий относительно того, когда сеанс выполняет вызовы 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() возвращает его в пул.

Ответ 2

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

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

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

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