2010-02-16 35 views
5

Tôi có mối quan hệ cha mẹ con giữa hai thực thể (Phụ huynh và Trẻ em).Xóa một mục khỏi bộ sưu tập (NHibernate)

lập bản đồ chuyên của tôi là như sau:

<class name="Parent" table="Parents"> 
    ... 
    <bag name="Children" cascade="all"> 
     <key column="ParentID"></key> 
     <one-to-many class="Child"></one-to-many> 
    </bag> 
</class> 

Tôi muốn thực hiện như sau:

someParent.Children.Remove(someChild); 

Lớp trẻ em có một tham chiếu đến một tầng lớp phụ huynh, Type. Mối quan hệ trông giống như

relation diagram

Lưu ý: Tôi xin lỗi vì sự url phi liên kết trên, tôi dường như không thể vượt qua các dấu hoa thị trong chuỗi url sử dụng Markup

Do này mối quan hệ, khi mã trên được gọi, thay vì một truy vấn DELETE, một truy vấn UPDATE được tạo ra để loại bỏ ParentID khỏi bảng con (đặt thành null).

Có thể buộc NHibernate xóa hoàn toàn bản ghi con, khi bị xóa khỏi bộ sưu tập Parent.Children không?

CẬP NHẬT

@ Giải pháp

giải pháp Rất hấp dẫn Spencer vì đây là một cái gì đó có thể được thực hiện trong các lớp học trong tương lai. Tuy nhiên, do các phiên làm việc được xử lý (trong trường hợp cụ thể của tôi) trong mẫu kho lưu trữ, điều này là gần như không thể vì chúng ta sẽ phải vượt qua các loại phiên (CallSessionContext/WebSessionContext) tùy thuộc vào ứng dụng.

@ Giải pháp của Jamie

Đơn giản và nhanh chóng thực hiện, tuy nhiên tôi đã nhấn một khối đường khác. Thực thể con tôi trông giống như sau: entity object

Khi sử dụng phương pháp mới, NHibernate tạo tuyên bố cập nhật thiết lập TypeID và ParentID thành null, trái ngược với xóa hoàn toàn. Nếu tôi bỏ lỡ một cái gì đó trong quá trình thực hiện, hãy cho tôi biết vì phương pháp này sẽ không đau để tiến lên phía trước.

@The One-Shot-Delete solution described here, phác thảo một ý tưởng hủy kết hợp bộ sưu tập để buộc xóa một lần. Kết quả tương tự như trên tuy nhiên, một tuyên bố cập nhật được ban hành.

//Instantiate new collection and add persisted items 
List<Child> children = new List<Child>(); 
children.AddRange(parent.Children); 

//Find and remove requested items from new collection 
var childrenToRemove = children 
    .Where(c => c.Type.TypeID == 1) 
    .ToList(); 

foreach (var c in childrenToRemove) { children.Remove(m); } 
parent.Children = null; 

//Set persisted collection to new list 
parent.Children = Children; 

Giải pháp

Took một chút đào, nhưng giải pháp của Jamie đã qua với một số sửa đổi bổ sung. Đối với độc giả trong tương lai, dựa trên mô hình của tôi lớp trên:

Loại bản đồ - Inverse = true, Cascade = tất cả các bản đồ chuyên

- Inverse = true, Cascade = all-xóa-mồ côi

Hủy bỏ các phương pháp như được mô tả trong các giải pháp của Jamie.Điều này tạo ra một tuyên bố xóa duy nhất cho mỗi mục mồ côi, vì vậy có khả năng điều chỉnh trong tương lai, tuy nhiên kết quả cuối cùng là thành công.

Trả lời

1

Thay vì để lộ IList<Child>, kiểm soát quyền truy cập vào bộ sưu tập thông qua một phương pháp:

RemoveChild(Child child) 
{ 
    Children.Remove(child); 
    child.Parent = null; 
    child.Type.RemoveChild(child); 
} 

Type.RemoveChild sẽ trông tương tự nhưng bạn sẽ phải cẩn thận để không đặt nó vào một vòng lặp vô hạn gọi của nhau RemoveChild phương pháp.

0

Tôi không nghĩ rằng điều này là chính xác có thể vì Hibernate không có cách nào để biết liệu bản ghi có bị mồ côi hay không. Nó có thể kiểm tra xem các lớp khác có liên quan đến lớp con không, nhưng sau đó nó sẽ giả định rằng nó nhận thức được toàn bộ cấu trúc DB có thể không phải là trường hợp.

Tuy nhiên, bạn hoàn toàn không may mắn. Bằng cách sử dụng giao diện IList kết hợp với một giao diện ICascadeDeleteChild tùy chỉnh mà bạn tạo, bạn có thể đưa ra một giải pháp khá liền mạch. Dưới đây là các bước cơ bản.

  1. Tạo lớp học hít vào IList và IList <> và gọi nó là CascadeDeleteList hoặc gì đó dọc theo các dòng đó.
  2. Tạo danh sách .Net riêng tư bên trong lớp này và chỉ cần ủy quyền các cuộc gọi phương thức khác nhau vào Danh sách này.
  3. Tạo giao diện có tên ICascadeDeleteChild và đặt cho nó phương thức Xóa()
  4. Theo phương pháp Xóa cho CascadeDeleteList của bạn, hãy kiểm tra loại đối tượng cần xóa. Nếu nó thuộc loại ICascadeDeleteChild thì gọi đó là phương thức Delete.
  5. Thay đổi lớp Con của bạn để triển khai giao diện ICascadeDeleteChild.

Tôi biết nó có vẻ giống như một nỗi đau nhưng một khi điều này được thực hiện các giao diện này nên được đơn giản để cổng xung quanh.

+0

Tôi tin rằng điều này có thể đã làm tôi ngạc nhiên trên con đường bên phải, khối đường đang được: thiết lập trong mô hình kho lưu trữ (ví dụ, trong trường hợp này phương thức Delete sẽ gọi phương thức lưu trữ của chính nó) và cũng có thể sử dụng điều này với ngữ cảnh phiên khác nhau (ví dụ: CallSessionContext vs WebSessionContext) –

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