NHibernate ISession Flush: Sử dụng nó ở đâu và khi nào, và tại sao?


187

Một trong những điều khiến tôi hoàn toàn bối rối là việc sử dụng session.Flush, kết hợp với session.Commit, và session.Close.

Đôi khi session.Closehoạt động, ví dụ, nó cam kết tất cả những thay đổi mà tôi cần. Tôi biết tôi cần sử dụng cam kết khi tôi có một giao dịch hoặc một đơn vị công việc với một số lần tạo / cập nhật / xóa, để tôi có thể chọn quay lại nếu xảy ra lỗi.

Nhưng đôi khi tôi thực sự bị cản trở bởi logic đằng sau session.Flush. Tôi đã thấy các ví dụ mà bạn có session.SaveOrUpdate()theo sau bởi một lần xả, nhưng khi tôi loại bỏ Flush thì nó vẫn hoạt động tốt. Đôi khi tôi gặp phải lỗi trong câu lệnh Flush nói rằng phiên đã hết thời gian và loại bỏ nó để đảm bảo rằng tôi không gặp phải lỗi đó.

Có ai có một hướng dẫn tốt về việc sử dụng Flush ở đâu hoặc khi nào không? Tôi đã kiểm tra tài liệu NHibernate cho việc này, nhưng tôi vẫn không thể tìm thấy câu trả lời đơn giản.

Câu trả lời:


236

Tóm tắt:

  1. Luôn sử dụng giao dịch
  2. Đừng sử dụng Close(), thay vào đó hãy bọc các cuộc gọi của bạn vào ISessionmột usingcâu lệnh bên trong hoặc quản lý vòng đời của ISession của bạn ở một nơi khác .

Từ tài liệu :

Thỉnh thoảng ISessionsẽ thực thi các câu lệnh SQL cần thiết để đồng bộ hóa trạng thái kết nối ADO.NET với trạng thái của các đối tượng được giữ trong bộ nhớ. Quá trình này, tuôn ra, xảy ra theo mặc định tại các điểm sau

  • từ một số lời mời của Find()hoặcEnumerable()
  • từ NHibernate.ITransaction.Commit()
  • từ ISession.Flush()

Các câu lệnh SQL được ban hành theo thứ tự sau

  1. tất cả các phần chèn vào thực thể, theo cùng thứ tự các đối tượng tương ứng đã được lưu bằng cách sử dụng ISession.Save()
  2. tất cả các cập nhật thực thể
  3. tất cả các bộ sưu tập xóa
  4. tất cả các phần tử xóa bộ sưu tập, cập nhật và chèn
  5. tất cả các bộ sưu tập chèn
  6. tất cả các thực thể xóa, theo cùng một thứ tự các đối tượng tương ứng đã bị xóa bằng cách sử dụng ISession.Delete()

(Một ngoại lệ là các đối tượng sử dụng tạo ID gốc được chèn khi chúng được lưu.)

Ngoại trừ khi bạn khám phá Flush(), hoàn toàn không có gì đảm bảo về thời điểm Phiên thực hiện các cuộc gọi ADO.NET, chỉ có thứ tự thực hiện chúng . Tuy nhiên, NHibernate đảm bảo rằng các ISession.Find(..)phương thức sẽ không bao giờ trả lại dữ liệu cũ; Họ cũng sẽ không trả lại dữ liệu sai.

Có thể thay đổi hành vi mặc định để việc xả nước xảy ra ít thường xuyên hơn. Các FlushModelớp học định nghĩa ba chế độ khác nhau: chỉ tuôn ra tại cam kết thời gian (và chỉ khi NHibernate ITransactionAPI được sử dụng), tuôn ra tự động bằng cách sử dụng giải thích thói quen, hoặc không bao giờ tuôn ra trừ khi Flush()được gọi một cách rõ ràng. Chế độ cuối cùng hữu ích cho các đơn vị công việc chạy dài, trong đó một ISessionđược giữ mở và ngắt kết nối trong một thời gian dài.

...

Cũng tham khảo phần này :

Kết thúc một phiên bao gồm bốn giai đoạn riêng biệt:

  • tuôn ra phiên
  • cam kết giao dịch
  • đóng phiên
  • xử lý ngoại lệ

Rửa sạch phiên

Nếu bạn tình cờ sử dụng ITransactionAPI, bạn không cần phải lo lắng về bước này. Nó sẽ được thực hiện ngầm khi giao dịch được cam kết. Nếu không, bạn nên gọi ISession.Flush()để đảm bảo rằng tất cả các thay đổi được đồng bộ hóa với cơ sở dữ liệu.

Cam kết giao dịch cơ sở dữ liệu

Nếu bạn đang sử dụng API NHransnate ITransaction, thì giao diện này sẽ như sau:

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

Nếu bạn đang tự mình quản lý các giao dịch ADO.NET, bạn nên Commit()giao dịch ADO.NET theo cách thủ công .

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

Nếu bạn quyết định không cam kết thay đổi của mình:

tx.Rollback();  // rollback the transaction

hoặc là:

currentTransaction.Rollback();

Nếu bạn khôi phục giao dịch, bạn nên đóng ngay lập tức và hủy phiên hiện tại để đảm bảo rằng trạng thái nội bộ của NHibernate là nhất quán.

Đóng cửa ISession

Một cuộc gọi để ISession.Close()đánh dấu sự kết thúc của một phiên. Hàm ý chính của Close () là kết nối ADO.NET sẽ bị hủy bỏ bởi phiên.

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

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

Nếu bạn đã cung cấp kết nối của riêng mình, hãy Close()trả về một tham chiếu đến nó, để bạn có thể đóng nó theo cách thủ công hoặc đưa nó trở lại nhóm. Nếu không thì Close()trả nó về hồ bơi.


2
đối với tôi, dòng này là chìa khóa: "Ý nghĩa chính của Close () là kết nối ADO.NET sẽ bị hủy bỏ bởi phiên." nếu bạn không gọi ISession. Đóng (), các kết nối của bạn sẽ được lấp đầy cho đến khi bạn nhận được thời gian chờ db. : o
dave thieben

Chúng tôi thường: mở phiên phiên.BeginTransaction () làm việc ... session.Transaction.Commit () session.BeginTransaction () làm việc ... session.Transaction.Commit () session.BeginTransaction () làm việc .. session.Transaction.Commit () phiên xử lý.
Agile Jedi

Brilliant ghi-up và +1 và vv - tuy nhiên tôi nghĩ rằng một chỉnh sửa có thể được yêu cầu bởi vì bạn nói ở đầu "Không bao giờ sử dụng chặt chẽ" và sau đó "Nếu bạn rollback giao dịch bạn nên ngay lập tức thân thiết và loại bỏ các phiên hiện tại"
SpaceBison

Có thể thay đổi thứ tự của các câu lệnh SQL. Ý tôi là tôi cần thực hiện cập nhật trên một đối tượng thực thể và hơn là chèn vì tôi có một ràng buộc trong bảng tương ứng.
bob_saginowski

14

Bắt đầu từ NHibernate 2.0, các giao dịch được yêu cầu cho các hoạt động DB. Do đó, ITransaction.Commit()cuộc gọi sẽ xử lý bất kỳ xả nước cần thiết. Nếu vì lý do nào đó bạn không sử dụng các giao dịch NHibernate, thì sẽ không có tự động xóa phiên.


1

Thỉnh thoảng, ISession sẽ thực thi các câu lệnh SQL cần thiết để đồng bộ hóa trạng thái của kết nối ADO.NET với trạng thái của các đối tượng được giữ trong bộ nhớ.

Và luôn luôn sử dụng

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

sau khi các thay đổi được cam kết hơn các thay đổi này để lưu vào cơ sở dữ liệu, chúng tôi sử dụng giao dịch.Commit ();


0

Đây là hai ví dụ về mã của tôi, nơi nó sẽ thất bại nếu không có phiên.Flush ():

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

ở phần cuối của điều này, bạn có thể thấy một phần mã nơi tôi đặt chèn nhận dạng, lưu thực thể sau đó xóa, sau đó đặt tắt nhận dạng. Nếu không có sự tuôn ra này, dường như thiết lập chèn và tắt nhận dạng sau đó lưu thực thể.

Việc sử dụng Flush () cho tôi nhiều quyền kiểm soát hơn những gì đang diễn ra.

Đây là một ví dụ khác:

Gửi tin nhắn NServiceBus bên trong TransactionScope

Tôi không hiểu tại sao về điều này, nhưng Flush () đã ngăn lỗi của tôi xảy ra.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.