2010-07-20 22 views
6

Được rồi, tôi đã thấy một số bài viết hỏi gần như giống nhau nhưng các điểm khác nhau một chút.NHibernate FlushMode Auto Not Flushing Trước khi tìm

Đây là trường hợp điển hình: Tôi đang lưu/cập nhật thực thể và trong PHIÊN BẢN ĐẾN, tôi đang cố gắng lấy chúng từ cơ sở dữ liệu (sử dụng tiêu chí/tìm/đếm/etc) với FlushMode = Tự động. Vấn đề là: NHibernate không xóa các cập nhật trước khi truy vấn, vì vậy tôi nhận được dữ liệu không nhất quán từ cơ sở dữ liệu.

"Fair đủ", một số người sẽ nói, như tài liệu khẳng định:

Quá trình này, tuôn ra, xảy ra theo mặc định ở những điểm sau đây:

  • từ một số lời gọi của Tìm() hoặc Enumerable()
  • từ NHibernate.ITransaction.Commit()
  • từ ISession.Flush()

Chữ đậm "một số lời gọi" rõ ràng nói rằng NH không có trách nhiệm gì cả. IMO, tuy nhiên, chúng tôi có vấn đề nhất quán ở đây vì tài liệu cũng nêu rõ rằng:

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

Vì vậy, nếu tôi đang sử dụng CreateQuery (Tìm thay thế) và lọc cho các đơn vị với giá trị tài sản = 20, NH có thể KHÔNG thực thể trở lại với giá trị = 30, phải không? Nhưng đó là những gì xảy ra trong thực tế, bởi vì Flush không xảy ra tự động khi cần.

public void FlushModeAutoTest() 
{ 
    ISession session = _sessionFactory.OpenSession(); 
    session.FlushMode = FlushMode.Auto; 

    MappedEntity entity = new MappedEntity() { Name = "Entity", Value = 20 }; 
    session.Save(entity); 

    entity.Value = 30; 
    session.SaveOrUpdate(entity); 

    // RETURNS ONE ENTITY, WHEN SHOULD RETURN ZERO 
    var list = session.CreateQuery("from MappedEntity where Value = 20").List<MappedEntity>(); 

    session.Flush(); 
    session.Close(); 
} 

Sau khi tất cả: tôi hiểu sai, có phải lỗi hoặc đơn giản là tính năng không thể đoán trước để mọi người phải gọi Flush để đảm bảo công việc của mình?

Cảm ơn bạn.

Filipe

Trả lời

8

Tôi không phải là rất quen thuộc với các mã nguồn NHibernate nhưng phương pháp này từ việc thực hiện ISession trong bản phát hành 2.1.2.GA có thể trả lời câu hỏi:

/// <summary> 
/// detect in-memory changes, determine if the changes are to tables 
/// named in the query and, if so, complete execution the flush 
/// </summary> 
/// <param name="querySpaces"></param> 
/// <returns></returns> 
private bool AutoFlushIfRequired(ISet<string> querySpaces) 
{ 
    using (new SessionIdLoggingContext(SessionId)) 
    { 
     CheckAndUpdateSessionStatus(); 
     if (!TransactionInProgress) 
     { 
      // do not auto-flush while outside a transaction 
      return false; 
     } 
     AutoFlushEvent autoFlushEvent = new AutoFlushEvent(querySpaces, this); 
     IAutoFlushEventListener[] autoFlushEventListener = listeners.AutoFlushEventListeners; 
     for (int i = 0; i < autoFlushEventListener.Length; i++) 
     { 
      autoFlushEventListener[i].OnAutoFlush(autoFlushEvent); 
     } 
     return autoFlushEvent.FlushRequired; 
    } 
} 

tôi thực hiện việc này để có nghĩa là tự động tuôn ra sẽ chỉ đảm bảo tính nhất quán bên trong một giao dịch, điều này có ý nghĩa gì đó. Hãy thử viết lại bài kiểm tra của bạn bằng cách sử dụng một giao dịch, tôi rất tò mò nếu điều đó sẽ khắc phục được sự cố.

+0

tks Thiên Chúa, bạn nói đúng! :) Sử dụng một giao dịch rõ ràng xung quanh khối mã đã giải quyết được vấn đề. Chúng tôi có thể sử dụng tiêu chí, tạo truy vấn, bất cứ điều gì, thay đổi đã được cam kết và kết quả truy vấn vượt qua bài kiểm tra. Cám ơn bạn một lần nữa! Tôi sẽ đề nghị NH nhóm cập nhật tài liệu và nêu rõ rằng chức năng tự động tuôn ra chỉ hoạt động bên trong một giao dịch rõ ràng, hy vọng điều này sẽ giúp nghi ngờ trong tương lai. – jfneis

+0

Bạn được chào đón. Câu hỏi hay, tôi chưa bao giờ hiểu điều này cho đến bây giờ. –

+0

Rất cám ơn! Nó giải quyết vấn đề của tôi. –

0

quản lý và điều chỉnh ngủ đông là một biểu mẫu.

tại sao bạn đặt giá trị ban đầu là 20, lưu, sau đó thay đổi thành 30?

Là một vấn đề của thực tế, nếu bạn đang sửa đổi phiên, sau đó truy vấn phiên, bạn có thể muốn xóa rõ ràng giữa các hoạt động đó. Bạn có thể có một hit hiệu suất nhỏ (sau khi tất cả, sau đó bạn không cho phép hibernate tối ưu hóa phiên đỏ bừng), nhưng bạn có thể xem lại nếu nó trở thành một vấn đề.

Bạn trích dẫn rằng "các phương thức session.find sẽ không bao giờ trả về dữ liệu cũ". Tôi sẽ sửa đổi mã của bạn để sử dụng tìm thay vì createQuery để xem nó có hoạt động hay không.

+0

Tôi đang thiết lập và thay đổi để kiểm tra hành vi, mã thực của tôi không giống như thế này. Tôi đang sử dụng CreateQuery vì Tìm không được chấp nhận và CreateQuery được đề xuất thay thế cho nó. – jfneis

2

Nếu bạn nghĩ về nó, truy vấn trong ví dụ của bạn phải luôn đi đến db. Phiên này không phải là bộ nhớ cache hoàn chỉnh của tất cả các bản ghi trong db. Vì vậy, có có thể là các thực thể khác có giá trị là 20 trên đĩa. Và kể từ khi bạn không cam kết() một giao dịch hoặc tuôn ra() phiên NH không có cách nào để biết "xem" mà bạn muốn truy vấn (DB | Session).

Nó có vẻ như là "Thực hành tốt nhất" là để làm tất cả mọi thứ (được & bộ) bên trong giao dịch rõ ràng:

using(var session = sessionFactory.OpenSession()) 
using(var tx = session.BeginTransaction()) 
{ 
    // execute code that uses the session 
    tx.Commit(); 
} 

Xem here cho một loạt các chi tiết.

+0

chúng tôi đồng ý rằng phiên không phải là bộ đệm cơ sở dữ liệu đầy đủ và rõ ràng là NH sẽ truy vấn DB và sẽ có một bản ghi khác. Ở đây có thỏa thuận: NH của doc nói rằng NH sẽ chăm sóc dữ liệu này bên trong phiên và cam kết nó ** tự động **. Tôi đồng ý rằng cam kết tx hoặc đỏ bừng phiên sẽ làm cho nó hoạt động, nhưng vì vậy chúng tôi có thể suy ra rằng các tài liệu đã lỗi thời? Hay tệ nhất là: liệu chúng ta có thể suy ra rằng nó đã hoạt động một lần nhưng bây giờ nó không còn nữa? – jfneis