NHibernate ISession Флеш:Где и когда его использовать и почему?
-
09-06-2019 - |
Вопрос
Одна из вещей, которая меня совершенно сбивает с толку, - это использование session.Flush
, в сочетании с session.Commit
, и session.Close
.
Иногда session.Close
работает, например, он фиксирует все изменения, которые мне нужны.Я знаю, что мне нужно использовать фиксацию, когда у меня есть транзакция или единица работы с несколькими созданиями / обновлениями / удалениями, чтобы я мог выбрать откат в случае возникновения ошибки.
Но иногда я действительно захожу в тупик из-за логики, стоящей за этим session.Flush
.Я видел примеры, когда у вас есть session.SaveOrUpdate()
за этим следует промывка, но когда я удаляю промывку, она все равно работает нормально.Иногда я сталкиваюсь с ошибками в операторе Flush, говорящими о том, что время ожидания сеанса истекло, и, удалив его, я убедился, что я не столкнулся с этой ошибкой.
Есть ли у кого-нибудь хорошие рекомендации относительно того, где и когда использовать Флеш?Я просмотрел документацию NHibernate для этого, но я все еще не могу найти прямого ответа.
Решение
Кратко:
- Всегда используйте транзакции
- Не используйте
Close()
, вместо этого переносите свои вызовы наISession
внутриusing
заявление или управляйте жизненным циклом вашей ISession где-нибудь в другом месте.
От документация:
Время от времени
ISession
выполнит инструкции SQL, необходимые для синхронизации состояния соединения ADO.NET с состоянием объектов, хранящихся в памяти.Этот процесс, flush, выполняется по умолчанию в следующих точках
- из некоторых призывов
Find()
илиEnumerable()
- От
NHibernate.ITransaction.Commit()
- От
ISession.Flush()
Инструкции SQL выдаются в следующем порядке
- все вставки объектов выполняются в том же порядке, в каком соответствующие объекты были сохранены с использованием
ISession.Save()
- все обновления объекта
- все удаления коллекции
- все удаления, обновления и вставки элементов коллекции
- все вставки коллекции
- все удаления объектов выполняются в том же порядке, в каком были удалены соответствующие объекты с помощью
ISession.Delete()
(Исключением является то, что объекты, использующие генерацию собственных идентификаторов, вставляются при их сохранении.)
За исключением тех случаев, когда вы объясняете
Flush()
, нет абсолютно никаких гарантий относительно того, когда сеанс выполняет ADO.NET вызовы, только порядок, в котором они выполняются.Однако NHibernate гарантирует, чтоISession.Find(..)
методы никогда не вернут устаревшие данные;они также не вернут неверные данные.Можно изменить поведение по умолчанию, чтобы сброс выполнялся реже.Тот Самый
FlushMode
класс определяет три различных режима:сбрасывать только во время фиксации (и только тогда, когда NHibernateITransaction
Используется 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
или:
currentTransaction.Rollback();
Если вы откатываете транзакцию, вы должны немедленно закрыть и отменить текущий сеанс, чтобы убедиться, что внутреннее состояние NHibernate является согласованным.
Закрытие ISession
Призыв к
ISession.Close()
знаменует окончание сеанса.Основное значение Close() заключается в том, что ADO.NET соединение будет разорвано сеансом.tx.Commit(); sess.Close(); sess.Flush(); currentTransaction.Commit(); sess.Close();
Если вы предоставили свое собственное подключение,
Close()
возвращает ссылку на него, так что вы можете вручную закрыть его или вернуть в пул.В противном случаеClose()
возвращает его в пул.
Другие советы
Начиная с NHibernate 2.0, для операций с базой данных требуются транзакции.Следовательно, ITransaction.Commit()
call выполнит любую необходимую промывку.Если по какой-то причине вы не используете транзакции NHibernate, то автоматической очистки сеанса не будет.
Время от времени ISession будет выполнять инструкции SQL, необходимые для синхронизации состояния соединения ADO.NET с состоянием объектов, хранящихся в памяти.
И всегда используйте
using (var transaction = session.BeginTransaction())
{
transaction.Commit();
}
после фиксации изменений для сохранения этих изменений в базе данных мы используем транзакцию.Commit();
Вот два примера моего кода, в которых без сеанса произошел бы сбой.Flush():
http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html
в конце этого вы можете увидеть раздел кода, где я включаю identity insert, сохраняю объект, затем удаляю, затем отключаю identity insert.Без этой очистки казалось, что он включает и выключает вставку идентификатора, а затем сохраняет объект.
Использование Flush() дало мне больше контроля над происходящим.
Вот еще один пример:
Отправка сообщения NServiceBus внутри TransactionScope
Я не совсем понимаю, почему в этом случае, но функция Flush() предотвратила возникновение моей ошибки.