2010-02-05 32 views
9

Tôi có một thực thể được gọi là Sách có thể có danh sách nhiều sách hơn được gọi là RelatedBooks.Thành thạo NHibernate Tự Tham khảo Nhiều người Nhiều người

Các thực thể Sách viết tắt trông giống thích này:

public class Book 
{ 
     public virtual long Id { get; private set; } 

     public virtual IList<Book> RelatedBooks { get; set; } 
} 

Đây là những gì các bản đồ trông giống như đối với mối quan hệ này

HasManyToMany(x => x.RelatedBooks) 
       .ParentKeyColumn("BookId") 
       .ChildKeyColumn("RelatedBookId") 
       .Table("RelatedBooks") 
       .Cascade.SaveUpdate(); 

Dưới đây là một ví dụ về các dữ liệu mà sau đó được tạo ra trong Bảng RelatedBooks:

BookId  RelatedBookId 
1   2 
1   3 

Sự cố xảy ra khi tôi thử để xóa một cuốn sách. Nếu tôi xóa sách có ID là 1, mọi thứ đều hoạt động tốt và bảng RelatedBooks có hai bản ghi tương ứng bị xóa. Tuy nhiên nếu tôi cố gắng xóa các cuốn sách với một ID của 3, tôi nhận được lỗi "Tuyên bố DELETE xung đột với các hạn chế REFERENCE" FK5B54405174BAB605 ". Xung đột xảy ra trong cơ sở dữ liệu" Test ", bảng" dbo.RelatedBooks ", cột 'RelatedBookId ''.

Về cơ bản những gì đang xảy ra là không thể xóa sách vì bản ghi trong bảng RelatedBooks có phần tử liên quan đến 3 không bao giờ bị xóa.

Làm cách nào để xóa bản ghi đó khi tôi xóa sách?

EDIT

Sau khi thay đổi Cascade từ SaveUpdate() để tất cả(), cùng một vấn đề vẫn còn tồn tại nếu tôi cố gắng xóa Sách với một ID của 3. Ngoài ra với Cascade thiết lập để tất cả() , nếu xóa Sách có ID và 1 thì tất cả 3 sách (ID: 1, 2 và 3) sẽ bị xóa để không hoạt động.

Nhìn vào SQL được thực hiện khi phương thức Book.Delete() được gọi khi tôi xóa sách có ID là 3, có vẻ như câu lệnh SELECT đang xem cột sai (mà tôi giả định có nghĩa là SQL DELETE statment sẽ mắc lỗi tương tự, do đó không bao giờ xóa bản ghi đó). Dưới đây là SQL cho RelatedBook

SELECT relatedboo0_.BookId as BookId3_ 
     , relatedboo0_.RelatedBookId as RelatedB2_3_ 
     , book1_.Id as Id14_0_ 

FROM RelatedBooks relatedboo0_ 
    left outer join [Book] book1_ on relatedboo0_.RelatedBookId=book1_.Id 

WHERE relatedboo0_.BookId=3 

Các ĐÂU Statment nên tìm một cái gì đó như thế này cho thie trường hợp cụ thể:

WHERE relatedboo0_.RelatedBookId = 3 

SOLUTION

Đây là những gì tôi phải làm gì để có được nó hoạt động cho mọi trường hợp

Lập bản đồ:

HasManyToMany(x => x.RelatedBooks) 
       .ParentKeyColumn("BookId") 
       .ChildKeyColumn("RelatedBookId") 
       .Table("RelatedBooks"); 

Code:

var book = currentSession.Get<Book>(bookId); 

if (book != null) 
{ 
    //Remove all of the Related Books 
    book.RelatedBooks.Clear(); 

    //Get all other books that have this book as a related book 
    var booksWithRelated = currentSession.CreateCriteria<Book>() 
           .CreateAlias("RelatedBooks", "br") 
           .Add(Restrictions.Eq("br.Id", book.Id)) 
           .List<Book>(); 

    //Remove this book as a Related Book for all other Books 
    foreach (var tempBook in booksWithRelated) 
    { 
     tempBook.RelatedBooks.Remove(book); 
     tempBook.Save(); 
    } 

    //Delete the book 
    book.Delete(); 
} 
+0

Bạn đang ở trên đi đúng hướng nhưng giải pháp mà sẽ là rất không hiệu quả bởi vì nó tải ALL sách sau đó lọc chúng. Bạn nên tìm ra cách viết lại nó để chỉ trả lại những cuốn sách có sách bị xóa trong bộ sưu tập của họ. Bạn cũng có thể xem xét thực hiện thao tác này thông qua SQL. –

+0

Cảm ơn bạn đã tư vấn. Đã thêm truy vấn tiêu chí NHibernate để chỉ nhận những sách đó. – Jeremy

Trả lời

4

Thay vì thiết lập các thuộc tính cascade, tôi nghĩ rằng bạn cần chỉ đơn giản là làm trống bộ sưu tập RelatedBooks trước khi xóa một cuốn sách.

book.RelatedBooks.Clear(); 
session.Delete(book); 

Xóa tầng thường không được thực hiện trong mối quan hệ nhiều-nhiều vì nó sẽ xóa đối tượng ở đầu kia của mối quan hệ, trong trường hợp này là Sách.

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