ฟลูออเรสเซนต์ NHibernate Flush: ใช้ที่ไหนและเมื่อไรและทำไม?


187

หนึ่งในสิ่งที่ได้รับฉันสับสนอย่างทั่วถึงคือการใช้session.Flushร่วมกับและsession.Commitsession.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 ITransactionAPI จะใช้) ล้างโดยอัตโนมัติโดยใช้อธิบายกิจวัตรประจำวันหรือไม่เคยล้างเว้นแต่Flush()จะเรียกว่าอย่างชัดเจน โหมดสุดท้ายมีประโยชน์สำหรับหน่วยงานที่ใช้เวลาทำงานนานซึ่งมีการISessionเปิดและยกเลิกการเชื่อมต่อเป็นเวลานาน

...

ดูที่หมวดนี้ด้วย :

การสิ้นสุดเซสชันจะมีสี่ขั้นตอนที่แตกต่างกัน:

  • ล้างเซสชั่น
  • กระทำธุรกรรม
  • ปิดเซสชัน
  • จัดการข้อยกเว้น

ล้างเซสชั่น

หากคุณกำลังใช้ITransactionAPI อยู่คุณไม่จำเป็นต้องกังวลเกี่ยวกับขั้นตอนนี้ มันจะถูกดำเนินการโดยนัยเมื่อมีการทำธุรกรรม มิฉะนั้นคุณควรโทรติดต่อ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()ส่งคืนไปยังพูล


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

หลังจากการเปลี่ยนแปลงมีความมุ่งมั่นกว่าการเปลี่ยนแปลงนี้เพื่อบันทึกลงในฐานข้อมูลที่เราใช้ transaction.Commit ();


0

นี่คือสองตัวอย่างของรหัสของฉันที่มันจะล้มเหลวโดยไม่ต้อง session.Flush ():

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

ในตอนท้ายของสิ่งนี้คุณจะเห็นส่วนของรหัสที่ฉันตั้งค่าการแทรกตัวตนบันทึกเอนทิตีแล้วล้างออกจากนั้นตั้งค่าการแทรกตัวตน ดูเหมือนว่าเป็นการตั้งค่าการเปิดและปิดการระบุตัวตนแล้วบันทึกเอนทิตี

การใช้ Flush () ทำให้ฉันควบคุมสิ่งที่เกิดขึ้นได้มากขึ้น

นี่เป็นอีกตัวอย่าง:

การส่งข้อความ NServiceBus ภายใน TransactionScope

ฉันไม่เข้าใจว่าทำไมในสิ่งนี้ แต่ Flush () ป้องกันข้อผิดพลาดของฉันเกิดขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.