2011-01-21 29 views
7

Tôi đang có một hành vi kỳ lạ với nhibernate. Vấn đề là nhibernate thực hiện cập nhật trước khi xóa một thực thể. Tôi có một lớp Hạng và một lớp Sản phẩm. Danh mục có túi sản phẩm. Khi tôi loại bỏ một sản phẩm từ loại, nhibernate hiện sau:NHibernate cập nhật hàng trước khi xóa nó?

  • Nó cập nhật đơn vị sản phẩm mà tôi lấy ra từ bộ sưu tập
  • Nó xóa đơn vị sản phẩm từ cơ sở dữ liệu.

Dưới đây là bản đồ

<class name="Category"> 
    <id name="Id"> 
     <generator class="hilo" /> 
    </id> 
    <property name="Name" lazy="false" length="20" /> 

    <bag name="Products" cascade="all-delete-orphan" lazy="false" 
inverse="false"> 
     <key column="CategoryId" /> 
     <one-to-many class="Product" /> 
    </bag> 
    </class> 

    <class name="Product"> 
    <id name="Id"> 
     <generator class="hilo" /> 
    </id> 
    <property name="Name" lazy="false" /> 
    <property name="Discontinued" lazy="false" /> 
    <property name="Price" lazy="false" /> 
    <many-to-one name="Category" 
      class="Category" 
      column="CategoryId" 
      cascade="none" /> 
    </class> 

Dưới đây là đoạn code

using (var session = NHibernateHelper.OpenSession()) 
    using (var transaction = session.BeginTransaction()) 
    { 
     var c1 = session.Load<Category>(32768); 
     c1.Ps.RemoveAt(0); 

     session.SaveOrUpdate(c1); 
     transaction.Commit(); 
    } 

và đây là kết quả:

exec sp_executesql N'UPDATE Product SET CategoryId = null WHERE 
CategoryId = @p0 AND Id = @p1',N'@p0 int,@p1 int',@p0=32768,@p1=65537 
go 

exec sp_executesql N'DELETE FROM Product WHERE Id = @p0',N'@p0 
int',@p0=65537 
go 

Bất cứ ai có thể giải thích hành vi kỳ lạ này?

Cảm ơn.

Trả lời

12

Thay đổi nghịch đảo đúng theo định nghĩa của bạn cho Túi sản phẩm của bạn trên Danh mục. Đặt nghịch đảo thành false cho NHibernate biết rằng đối tượng Category là chủ sở hữu của khóa trên mối quan hệ.

Với bộ nghịch đảo thành sai trên bộ sưu tập Sản phẩm, NHibernate coi Danh mục là chủ sở hữu của mối quan hệ. Vì vậy, khi bộ sưu tập Sản phẩm thay đổi, nó sẽ đưa ra tuyên bố cập nhật để xóa Sản phẩm khỏi Danh mục. Sau đó, việc xóa xảy ra vì Sản phẩm đã bị xóa.

+0

Cảm ơn, bài đăng của bạn rất hữu ích :) – Davita

0

EDIT: Rất tiếc, đã bị nhầm lẫn bởi mã; Ps không phải là thuộc tính mô tả. Điều xảy ra trong trường hợp này là, vì cách bạn xóa Sản phẩm (bằng cách xóa nó khỏi bộ sưu tập trên Danh mục và sau đó lưu Danh mục), NHibernate trước hết loại bỏ tham chiếu đến Danh mục khỏi Sản phẩm, bởi vì Sản phẩm đó không thuộc về Category (đây là một bản dịch chính giữa các đối tượng và các bảng; trong OOP tham chiếu được tổ chức bởi đối tượng chứa, trong khi trong SQL nó được tổ chức bởi đối tượng chứa). Bây giờ bản ghi không thuộc về bất kỳ Danh mục nào; đó là mồ côi, và bạn đã nói với NHibernate để làm sạch các tài liệu tham khảo mồ côi trong hành vi tầng của nó, do đó, nó thực hiện xóa.

Nếu bạn muốn làm điều đó chỉ với một câu lệnh SQL, hãy thử này:

using (var session = NHibernateHelper.OpenSession()) 
using (var transaction = session.BeginTransaction()) 
{ 
    var c1 = session.Load<Category>(32768); 
    var toDelete = c1.Ps[0]; 
    c1.Ps.RemoveAt(0); 

    session.Delete(toDelete); 
    transaction.Commit(); 
    //you shouldn't need to update the c1 object 
} 
+0

Hi keith, cảm ơn bạn đã trả lời. Bạn nói đúng, nhưng trong điều này istuation, tôi không xóa một thể loại, tôi chỉ cần loại bỏ một sản phẩm từ thể loại. Vì vậy, hoạt động này không đòi hỏi phải tách các tài liệu tham khảo và trong tình huống của tôi, điều này là không cần thiết chút nào. – Davita

-2

Hành vi này có vẻ bình thường đối với tôi. Tôi có ít kinh nghiệm với NHibernate, nhưng để xóa một bản ghi tôi tin rằng bạn thường gọi phương thức ISession.Delete, truyền vào đối tượng đại diện cho bản ghi mà bạn muốn xóa.

Trong trường hợp của bạn, bạn có thể có thể làm như sau:

// delete a product 
session.Delete(c1.Ps[0]); 

Hoặc, để được rõ ràng hơn:

// find the product that I want to delete 
var product = c1.Ps[0]; 

// now delete it 
session.Delete(product); 

Mã của bạn dường như được tham gia một cách vòng xoay của xóa Hồ sơ sản phẩm. Mã của bạn không xóa sản phẩm một cách rõ ràng, thay vào đó, nó đang hủy liên kết Bản ghi sản phẩm với bản ghi Danh mục đó. Đó là lý do tại sao NHibernate đang thực hiện cập nhật.

Lưu ý rằng trong lớp Hạng bạn đã xác định thuộc tính "xếp tầng" của mối quan hệ với lớp Sản phẩm như sau: cascade="all-delete-orphan". Bởi vì bản cập nhật của bạn khiến cho bản ghi Sản phẩm bị mồ côi, NHibernate có thể nhận ra rằng bản ghi Sản phẩm sẽ bị xóa, theo cài đặt thác của bạn và vì vậy tôi cho rằng đó là lý do tại sao nó quyết định thực thi lệnh xóa.

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