NHibernate ISession Flush: Де і коли його використовувати, і чому?


187

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

Іноді session.Closeпрацює, наприклад, він здійснює всі необхідні мені зміни. Я знаю, що мені потрібно використовувати фіксацію, коли у мене є транзакція або одиниця роботи з кількома створеннями / оновленнями / видаленнями, щоб я міг вибрати відкат, якщо сталася помилка.

Але іноді я дійсно заважаю логіці позаду session.Flush. Я бачив приклади, коли за вами session.SaveOrUpdate()слідує флеш, але коли я виймаю Flush, він все одно працює добре. Іноді я стикаюся з помилками в операторі Flush, кажучи, що сеанс закінчився, і його видалення переконалося, що я не натрапив на цю помилку.

Хтось має хороші рекомендації щодо того, де або коли використовувати флеш? Я перевірив документацію NHibernate на це, але все ще не можу знайти прямої відповіді.

Відповіді:


236

Коротко:

  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()

(Винятком є ​​те, що об'єкти, які використовують нативний ID генерації, вставляються під час їх збереження.)

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

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

...

Також зверніться до цього розділу :

Закінчення сеансу включає чотири різних етапи:

  • промити сеанс
  • здійснити транзакцію
  • закрити сесію
  • обробляти винятки

Промивання сесії

Якщо ви користуєтесь ITransactionAPI, вам не потрібно турбуватися про цей крок. Він буде виконуватися неявно, коли транзакція здійснена. В іншому випадку вам слід зателефонувати, ISession.Flush()щоб переконатися, що всі зміни синхронізовані з базою даних.

Здійснення транзакції з базою даних

Якщо ви використовуєте програмний інтерфейс ITi-відповіді NHibernate, це виглядає так:

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.Close()позначення кінця сеансу. Основним наслідком Close () є те, що з'єднання ADO.NET буде відмовлено сеансом.

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

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

Якщо ви надали власне з'єднання, Close()повертаєте посилання на нього, тож ви можете його вручну закрити або повернути в пул. В іншому випадку Close()повертає його до пулу.


2
для мене цей рядок був ключовим: "Основним наслідком Close () є те, що з'єднання ADO.NET буде відмовлено сеансом." якщо ви не зателефонували за ISession.Close (), ваші з'єднання заповнюються, поки ви не отримаєте тайм-аут db. : o
dave thieben

Ми зазвичай: відкритий сеанс сесії.BeginTransaction () працює ... session.Transaction.Commit () session.BeginTransaction () робота ... session.Transaction.Commit () session.BeginTransaction () робота .. session.Transaction.Commit () розпорядження сесії.
Agile Jedi

Блискуче списання, +1 і т. Д. - однак, я думаю, що редагування може знадобитися, оскільки ви вгорі говорите "Ніколи не використовуйте закриття", а потім пізніше "Якщо ви відкажете транзакцію, слід негайно закрити та відмовитися від поточної сесії"
SpaceBison

Чи можна змінити порядок операторів SQL. Я маю на увазі, що мені потрібно виконати оновлення над об'єктом сутності, а потім вставити, тому що у мене є обмеження у відповідній таблиці.
bob_saginowski

14

Починаючи з NHibernate 2.0, для операцій з БД потрібні транзакції. Тому ITransaction.Commit()дзвінок буде обробляти будь-яку необхідну промивку. Якщо ви з якихось причин не використовуєте транзакції NHibernate, сеанс автоматичного промивання сеансу не відбудеться.


1

Час від часу ISession виконуватиме оператори SQL, необхідні для синхронізації стану з'єднання ADO.NET зі станом об'єктів, що зберігаються в пам'яті.

І завжди використовувати

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

після внесення змін, ніж це змінюється для збереження в базі даних, ми використовуємо транзакції.Commit ();


0

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

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

наприкінці цього ви можете побачити розділ коду, де я встановив вставку ідентифікації, збережіть сутність, а потім вимкніть, а потім встановіть вставку ідентифікації. Без цього потоку здавалося, що ви встановлюєте і вимикаєте ідентифікатор, а потім зберігаєте сутність.

Використання Flush () дало мені більше контролю над тим, що відбувається.

Ось ще один приклад:

Надсилання повідомлення NServiceBus всередині TransactionScope

Я не повністю розумію, чому саме на цьому, але Flush () запобіг моїй помилці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.