Làm thế nào để xóa đối tượng con trong NHibernate?


79

Tôi có một đối tượng cha có mối quan hệ một đến nhiều với một IList của các đối tượng con. Cách tốt nhất để xóa các đối tượng con là gì? Tôi không xóa phụ huynh. Đối tượng cha của tôi chứa IList của các đối tượng con. Đây là ánh xạ cho mối quan hệ một đến nhiều:

<bag name="Tiers" cascade="all">
  <key column="mismatch_id_no" />
  <one-to-many class="TGR_BL.PromoTier,TGR_BL"/>
</bag>

Nếu tôi cố gắng xóa tất cả các đối tượng khỏi bộ sưu tập bằng clear (), sau đó gọi SaveOrUpdate (), tôi nhận được ngoại lệ này:

System.Data.SqlClient.SqlException: Cannot insert the value NULL into column

Nếu tôi cố gắng xóa từng đối tượng con sau đó xóa chúng khỏi đối tượng chính, tôi nhận được một ngoại lệ:

deleted object would be re-saved by cascade

Đây là lần đầu tiên tôi xử lý việc xóa các đối tượng con trong NHibernate. Tôi đang làm gì sai?

chỉnh sửa: Chỉ để làm rõ - Tôi KHÔNG cố gắng xóa đối tượng mẹ, chỉ xóa các đối tượng con. Tôi có mối quan hệ được thiết lập như một với nhiều mối quan hệ với cha mẹ. Tôi có cần tạo mối quan hệ nhiều-một trên ánh xạ đối tượng con không?

Câu trả lời:


139

Bạn đang gặp lỗi đầu tiên vì khi bạn xóa các mục khỏi bộ sưu tập, chế độ hoạt động mặc định của NHibernate chỉ đơn giản là phá vỡ liên kết. Trong cơ sở dữ liệu, NHibernate cố gắng đặt cột khóa ngoại trên hàng con thành rỗng. Vì bạn không cho phép null trong cột đó, SQL Server sẽ gây ra lỗi. Xóa bộ sưu tập sẽ không nhất thiết phải xóa đối tượng con, nhưng có một cách để làm như vậy là đặt cascade = all-delete-orphan. Điều này thông báo cho NHibernate rằng nó nên xóa các hàng mới bị mồ côi thay vì đặt cột khóa ngoại.

Bạn đang gặp lỗi thứ hai vì khi bạn gọi SaveOrUpdate NHibernate trước tiên sẽ xóa tất cả các đối tượng con. Sau đó, vì không có mối quan hệ nào được đánh dấu là nghịch đảo, NHibernate cũng cố gắng đặt cột khóa ngoại trong bảng con của bạn thành null. Vì các hàng đã bị xóa, bạn nhận được lỗi thứ hai. Bạn cần đặt inverse = true ở một phía của mối quan hệ của mình để khắc phục điều này. Điều này thường được thực hiện ở phía một (khóa chính hoặc phụ huynh). Nếu bạn không làm điều này, NHibernate sẽ thực hiện các cập nhật phù hợp cho từng bên của mối quan hệ. Thật không may, chạy hai bản cập nhật không phải là điều thích hợp để làm.

Bạn nên luôn đánh dấu một mặt của các mối quan hệ của bạn là mặt nghịch đảo. Tùy thuộc vào cách bạn viết mã, bạn có thể có hoặc không cần sử dụng xếp tầng. Nếu bạn muốn tận dụng tính năng xóa một lần khi bạn đang cố gắng thực hiện bằng Clear (), bạn cần xác định tầng của mình.


Chỉ cần làm rõ - tôi chỉ xác định mối quan hệ trên đối tượng Cha ngay bây giờ. Tôi đã cố gắng đặt tầng trên đối tượng đó thành "all" và "all-delete-orphan" với kết quả giống nhau cả hai lần. Ý bạn là tôi cũng cần xác định mối quan hệ nhiều-một trên đối tượng con?
Mark Struzinski

Và trong trường hợp này, inverse = "true" thuộc đối tượng cha hay con?
Mark Struzinski

3
nó thuộc về lớp không giữ khóa ngoại ... thường là lớp cha.
pmlarocque

Cảm ơn vì lời giải thích này, một lần nữa, một vấn đề nghịch đảo lại khiến tôi không hiểu, và thấy nó được giải thích như thế này thực sự hữu ích.
Mark Dickinson

Điều này thực sự giúp giải quyết một vấn đề mà tôi đang gặp phải. Cảm ơn.
Robin Robinson

3

Theo câu trả lời của Chuck, tôi đã giải quyết vấn đề của mình bằng cách thêm Inverse = true trong ánh xạ phía cha:

Tin nhắn có nhiều MessageSentTo:

[HasMany(typeof(MessageSentTo), Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true)]
public IList<MessageSentTo> MessageSendTos
{
    get { return m_MessageSendTo; }
    set { m_MessageSendTo = value; }
}

Tôi đang sử dụng Castle ActiveRecord. Cảm ơn Chuck.


2

Hãy thử sử dụng merge () thay vì saveOrUpdate (). Ngoài ra, hãy đảm bảo dòng thác của bạn được đặt thành all-delete-orphan và mối quan hệ cha-con của bạn là không thể đảo ngược (inverse = true trên trường gốc và sau đó là trường con là id cha với not-null = true) .


2

Trong ví dụ của chúng tôi, chúng tôi có các danh mục với nhiều sản phẩm trong đó một sản phẩm không thể trống.

Bạn có thể khắc phục sự cố bằng cách xóa sản phẩm và xóa sản phẩm khỏi bộ sưu tập của phụ huynh trước khi xả nhưng chúng tôi vẫn đang tìm giải pháp tốt hơn cho vấn đề này.

product = pRepo.GetByID(newProduct.ProductID);
product.Category.Products.Remove(product);
pRepo.Delete(product);

Hy vọng nó sẽ giúp dù sao


1
Điều này yêu cầu một kho lưu trữ khác.
UpTheCreek

0

Thay đổi giá trị thuộc tính tầng từ "all" thành "all-delete-orphan".


Đã thử điều này. Tôi vẫn nhận được cùng một ngoại lệ.
Mark Struzinski

16
all-delete-orphan sẽ xóa con khi bạn xóa cha mẹ. nó không liên quan gì đến việc xóa những đứa trẻ như anh chàng này đang hỏi.
Kyle West

-3

đặt Not-Null = true trong ánh xạ của bạn trên cột gây ra sự cố. Tôi không chắc về cú pháp chính xác (xin lỗi).


Ok, tôi đặt cột thành not-null = "true" trên ánh xạ của đối tượng con. Vì vậy, tôi gọi phương thức clear () trên IList của các đối tượng con, sau đó thử một SaveOrUpdate (). Tôi vẫn gặp lỗi "Không thể chèn giá trị NULL vào cột". Tôi có đang làm điều gì khác sai không?
Mark Struzinski

lỗi được ném vào cột nào? Làm thế nào chính xác là bạn xóa các trẻ em trong mô hình của bạn?
Kyle West

Tôi đang gọi phương thức clear () trên đối tượng con Ilist trong đối tượng mẹ của tôi. Sau đó, tôi đang gọi SaveOrUpdate () trên cha mẹ.
Mark Struzinski
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.