2010-12-24 39 views
6

Tôi đã triển khai người nghe kiểm tra các thay đổi đối với các bảng trong ứng dụng của tôi bằng cách sử dụng IPreUpdateEventListenerIPreInsertEventListener và mọi thứ hoạt động ngoại trừ các mối quan hệ nhiều người không có dữ liệu bổ sung trong khi tham gia bảng (tức là tôi không có một POCO cho bảng tham gia).Kiểm tra mối quan hệ nhiều-nhiều trong NHibernate

Mỗi đối tượng có thể kiểm tra thực hiện giao diện IAuditable, do đó trình xử lý sự kiện sẽ kiểm tra xem POCO có thuộc loại IAuditable hay không và liệu nó có ghi lại bất kỳ thay đổi nào đối tượng không. Tra cứu bảng triển khai thực hiện IAuditableProperty inteface, vì vậy nếu thuộc tính của IAuditable POCO trỏ đến bảng tra cứu, các thay đổi được ghi lại trong nhật ký cho POCO chính.

Vì vậy, câu hỏi đặt ra là, làm cách nào để xác định tôi đang làm việc với một bộ sưu tập nhiều người và ghi lại những thay đổi trong bảng kiểm toán của tôi?

Chỉnh sửa: Tôi đang sử dụng NHibernate 2.1.2.4000

//first two checks for LastUpdated and LastUpdatedBy ommitted for brevity 
else if (newState[i] is IAuditable) 
{ 
    //Do nothing, these will record themselves separately 
} 
else if (!(newState[i] is IAuditableProperty) && (newState[i] is IList<object> || newState[i] is ISet)) 
{ 
    //Do nothing, this is a collection and individual items will update themselves if they are auditable 
    //I believe this is where my many-to-many values are being lost 
} 
else if (!isUpdateEvent || !Equals(oldState[i], newState[i]))//Record only modified fields when updating 
{ 
    changes.Append(preDatabaseEvent.Persister.PropertyNames[i]) 
     .Append(": "); 
    if (newState[i] is IAuditableProperty) 
    { 
     //Record changes to values in lookup tables 
     if (isUpdateEvent) 
     { 
      changes.Append(((IAuditableProperty)oldState[i]).AuditPropertyValue) 
       .Append(" => "); 
     } 
     changes.Append(((IAuditableProperty)newState[i]).AuditPropertyValue); 
    } 
    else 
    { 
     //Record changes for primitive values 
     if(isUpdateEvent) 
     { 
      changes.Append(oldState[i]) 
       .Append(" => "); 
     } 
     changes.Append(newState[i]); 
    } 
    changes.AppendLine(); 
} 
+0

Đào sâu hơn vào điều này, nó xuất hiện các sự kiện 'OnPreUpdate' và' OnPreInsert' của tôi thậm chí không kích hoạt khi tôi sửa đổi các bộ sưu tập nhiều thành nhiều, nhưng các thay đổi đang được lưu vào cơ sở dữ liệu. Đây có lẽ là hành vi mong đợi do một số ma thuật sâu sắc hơn của NHibernate, nhưng nó cảm thấy giống như một lỗi/ommision với khối lượng chưa rửa ... – Kendrick

Trả lời

3

Lý do rằng điều này sẽ không cháy được vì các bộ sưu tập đã không thay đổi, tức là họ vẫn đang cùng một ví dụ của ICollection đó là trước đó, tuy nhiên nội dung của các bộ sưu tập đã thay đổi.

Tôi đã tự tìm kiếm điều này và người nghe sự kiện không xử lý tình huống này. Điều này có thể đã được cố định cho v3.0 (nhưng không báo cho tôi về điều đó). Có một vài cách giải quyết không lý tưởng:

1) Đặt thuộc tính trên đối tượng tạo chuỗi đại diện cho bộ sưu tập nhằm mục đích kiểm tra.

2) Làm cho các mục trong bộ sưu tập triển khai giao diện để chúng được kiểm tra riêng lẻ.

Edit: Có một lựa chọn thứ ba:

"Thay vì một nhiều-nhiều, tôi có một nhiều-to-one sẽ bàn tham gia, và sau đó một one-to-many đến từ vào bảng thuộc tính. Tôi ẩn bảng kết nối POCO đằng sau logic của mỗi đầu của các kết nối nhiều-nhiều, nhưng vẫn phải triển khai đối tượng và tất cả các giao diện trên nó. "

+0

Tôi đã kết thúc bằng cách sử dụng tùy chọn thứ 3 - tạo một đối tượng rõ ràng cho bảng kết nối. Thay vì nhiều người, tôi có nhiều người đến bàn tham gia, và sau đó một người đến nhiều từ nó vào bảng tài sản. Tôi ẩn bảng tham gia POCO đằng sau logic của mỗi đầu của các kết nối nhiều-nhiều, nhưng vẫn phải thực hiện đối tượng và tất cả các giao diện trên nó. Nếu điều này có ý nghĩa, bạn có thể muốn thêm nó vào câu trả lời của bạn (vì vậy nó sẽ dễ đọc hơn trong nhận xét) – Kendrick

3

Nó chỉ ra rằng có thực sự là một cách để làm điều này thông qua sự kiện nghe mà không cần phải để lộ các bảng tham gia. Bạn chỉ cần thực hiện trình xử lý sự kiện của mình triển khai IPostCollectionRecreateEventListener hoặc IPreCollectionRecreateEventListener. Dựa trên thử nghiệm của tôi, các sự kiện này được kích hoạt cho các bộ sưu tập đã thay đổi bất cứ khi nào phiên bị xóa. Đây là mã trình xử lý sự kiện của tôi cho phương thức PostRecreateCollection.

public void OnPostRecreateCollection(PostCollectionRecreateEvent @event) 
     { 
      var session = @event.Session.GetSession(EntityMode.Poco); 
      var propertyBeingUpdated = @event.Session.PersistenceContext.GetCollectionEntry(@event.Collection).CurrentPersister.CollectionMetadata.Role; 

      var newCollectionString = @event.Collection.ToString(); 
      var oldCollection = (@event.Collection.StoredSnapshot as IList<object>).Select(o => o.ToString()).ToList(); 
      var oldCollectionString = string.Join(", ",oldCollection.ToArray()); 

      if (newCollectionString == oldCollectionString || (string.IsNullOrEmpty(newCollectionString) && string.IsNullOrEmpty(oldCollectionString))) 
       return; 

      User currentUser = GetLoggedInUser(session); 
      session.Save(new Audit 
      { 
       EntityName = @event.AffectedOwnerOrNull.GetType().Name, 
       EntityId = (int)@event.AffectedOwnerIdOrNull, 
       PropertyName = propertyBeingUpdated, 
       AuditType = "Collection Modified", 
       EventDate = DateTime.Now, 
       NewValue = newCollectionString, 
       OldValue = oldCollectionString, 
       AuditedBy = Environment.UserName, 
       User = currentUser 
      }); 
     } 

Phần khó khăn nhất là lấy tên của bộ sưu tập đang được cập nhật. Bạn phải chuỗi theo cách của bạn thông qua PersistenceContext để có được Persister cho bộ sưu tập cung cấp cho bạn quyền truy cập vào dữ liệu meta của nó.

Vì không có sự kiện hoặc người nghe nào được ghi lại, tôi không biết liệu sự kiện này có bị ném vào các tình huống khác ngoài tuôn ra không, nên có khả năng nó có thể tạo mục kiểm toán sai. Tôi dự định thực hiện thêm một số nghiên cứu trong khu vực đó.

+0

"Tôi dự định thực hiện thêm một số nghiên cứu trong khu vực đó". - bất kỳ bản cập nhật nào cho điều này? – SamuelKDavis

+0

Tôi thực sự đã triển khai dự án bằng cách sử dụng mã này một thời gian trước đây. Nhưng chúng tôi sử dụng nó trong một số tháng mà không có bất kỳ vấn đề rõ ràng. Không bảo đảm rõ ràng – AndrewSwerlick

Các vấn đề liên quan