NHibernate ISession Flush: Di mana dan kapan menggunakannya, dan mengapa?

187

Salah satu hal yang membuat saya benar-benar bingung adalah penggunaan session.Flush, dalam hubungannya dengan session.Commit, dan session.Close.

Terkadang session.Closeberhasil, misalnya, ia melakukan semua perubahan yang saya butuhkan. Saya tahu saya harus menggunakan komit ketika saya melakukan transaksi, atau unit kerja dengan beberapa menciptakan / memperbarui / menghapus, sehingga saya dapat memilih untuk mengembalikan jika kesalahan terjadi.

Tapi kadang-kadang saya benar-benar terhalang oleh logika di belakang session.Flush. Saya telah melihat contoh di mana Anda telah session.SaveOrUpdate()diikuti oleh siram, tetapi ketika saya menghapus Siram itu berfungsi dengan baik. Kadang-kadang saya mengalami kesalahan pada pernyataan Flush mengatakan bahwa sesi habis waktu, dan menghapusnya memastikan bahwa saya tidak mengalami kesalahan itu.

Adakah yang punya pedoman yang baik tentang di mana atau kapan menggunakan Flush? Saya telah memeriksa dokumentasi NHibernate untuk ini, tetapi saya masih tidak dapat menemukan jawaban langsung.

Jon Limjap
sumber

Jawaban:

236

Secara singkat:

  1. Selalu gunakan transaksi
  2. Jangan gunakan Close(), bukan membungkus panggilan Anda pada ISessiondi dalam usingpernyataan atau mengelola siklus hidup ISession Anda di tempat lain .

Dari dokumentasi :

Dari waktu ke waktu ISessionkehendak menjalankan pernyataan SQL yang diperlukan untuk menyinkronkan keadaan koneksi ADO.NET dengan keadaan objek yang disimpan dalam memori. Proses ini, flush, terjadi secara default di titik-titik berikut

  • dari beberapa doa Find()atauEnumerable()
  • dari NHibernate.ITransaction.Commit()
  • dari ISession.Flush()

Pernyataan SQL dikeluarkan dalam urutan berikut

  1. semua insersi entitas, dalam urutan yang sama objek terkait disimpan menggunakan ISession.Save()
  2. semua pembaruan entitas
  3. semua penghapusan koleksi
  4. semua penghapusan, pembaruan, dan sisipan elemen koleksi
  5. semua sisipan koleksi
  6. semua penghapusan entitas, dalam urutan yang sama objek terkait dihapus menggunakan ISession.Delete()

(Pengecualian adalah objek yang menggunakan generasi ID asli dimasukkan saat disimpan.)

Kecuali ketika Anda menjelaskannya Flush(), sama sekali tidak ada jaminan tentang kapan Sesi mengeksekusi panggilan ADO.NET, hanya urutan di mana mereka dieksekusi . Namun, NHibernate tidak menjamin bahwa ISession.Find(..)metode tidak akan pernah mengembalikan data basi; mereka juga tidak akan mengembalikan data yang salah.

Dimungkinkan untuk mengubah perilaku default sehingga flush terjadi lebih jarang. The FlushModekelas mendefinisikan tiga mode yang berbeda: hanya siram pada komit waktu (dan hanya jika NHibernate ITransactionAPI digunakan), siram otomatis menggunakan menjelaskan rutin, atau tidak pernah menyiram kecuali Flush()disebut secara eksplisit. Mode terakhir berguna untuk unit kerja yang berjalan lama, di mana sebuah ISessiontetap terbuka dan terputus untuk waktu yang lama.

...

Lihat juga bagian ini :

Mengakhiri sesi melibatkan empat fase berbeda:

  • siram sesi
  • melakukan transaksi
  • tutup sesi
  • menangani pengecualian

Menyiram Sesi

Jika Anda menggunakan ITransactionAPI, Anda tidak perlu khawatir tentang langkah ini. Ini akan dilakukan secara implisit ketika transaksi dilakukan. Kalau tidak, Anda harus menelepon ISession.Flush()untuk memastikan bahwa semua perubahan disinkronkan dengan database.

Melakukan transaksi basis data

Jika Anda menggunakan NHibernate ITransaction API, ini terlihat seperti:

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

Jika Anda mengelola sendiri transaksi ADO.NET, Anda harus secara manual Commit()melakukan transaksi ADO.NET.

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

Jika Anda memutuskan untuk tidak melakukan perubahan:

tx.Rollback();  // rollback the transaction

atau:

currentTransaction.Rollback();

Jika Anda mengembalikan transaksi, Anda harus segera menutup dan membuang sesi saat ini untuk memastikan bahwa kondisi internal NHibernate konsisten.

Menutup ISession

Panggilan untuk ISession.Close()menandai akhir sesi. Implikasi utama dari Close () adalah bahwa koneksi ADO.NET akan dilepaskan oleh sesi.

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

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

Jika Anda menyediakan koneksi Anda sendiri, Close()kembalikan referensi ke sana, sehingga Anda bisa menutupnya secara manual atau mengembalikannya ke pool. Kalau tidak, Close()kembalikan ke kolam renang.

Matt Hinze
sumber
2
bagi saya, baris ini adalah kunci: "Implikasi utama dari Close () adalah bahwa koneksi ADO.NET akan dilepaskan oleh sesi." jika Anda tidak memanggil ISession.Close (), koneksi Anda terisi hingga Anda mendapatkan db timeout. : o
dave thieben
Kami biasanya: membuka sesi sesi.BeginTransaksi () berfungsi ... sesi.Transaksi.Komentar () sesi.Transaksi pemula () bekerja ... sesi.Transaksi.Komentar () sesi.BeginTransaksi () bekerja .. sesi.Transaksi.Komitmen () buang sesi.
Agile Jedi
Tulisan brilian dan +1 dan lain-lain - namun saya pikir suntingan mungkin diperlukan karena Anda mengatakan di bagian atas "Jangan pernah gunakan tutup" dan kemudian "Jika Anda mengembalikan transaksi, Anda harus segera menutup dan membuang sesi saat ini"
SpaceBison
Bisakah urutan pernyataan SQL diubah. Maksud saya, saya perlu melakukan pembaruan pada objek entitas dan kemudian menyisipkan karena saya memiliki kendala dalam tabel terkait.
bob_saginowski
14

Mulai di NHibernate 2.0, transaksi diperlukan untuk operasi DB. Oleh karena itu, ITransaction.Commit()panggilan akan menangani pembilasan yang diperlukan. Jika karena alasan tertentu Anda tidak menggunakan transaksi NHibernate, maka tidak akan ada pembilasan sesi secara otomatis.

Sean Carpenter
sumber
1

Dari waktu ke waktu ISession akan menjalankan pernyataan SQL yang diperlukan untuk menyinkronkan keadaan koneksi ADO.NET dengan keadaan objek yang disimpan dalam memori.

Dan selalu gunakan

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

setelah perubahan dilakukan daripada perubahan ini untuk disimpan ke dalam basis data, kami menggunakan transaction.Commit ();

ganders
sumber
0

Berikut adalah dua contoh kode saya di mana ia akan gagal tanpa sesi.Flush ():

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

di akhir ini, Anda dapat melihat bagian kode tempat saya mengaktifkan penyisipan identitas, menyimpan entitas lalu menyiram, lalu mematikan penyisipan identitas. Tanpa flush ini tampaknya mengatur dan memasukkan identitas kemudian menyimpan entitas.

Penggunaan Flush () memberi saya lebih banyak kontrol atas apa yang sedang terjadi.

Ini adalah contoh lain:

Mengirim pesan NServiceBus di dalam TransactionScope

Saya tidak sepenuhnya mengerti mengapa yang satu ini, tetapi Flush () mencegah kesalahan saya terjadi.

Paul T Davies
sumber