NHibernate에서 자식 개체를 삭제하는 방법은 무엇입니까?


79

자식 개체의 IList와 일대 다 관계를 갖는 부모 개체가 있습니다. 자식 개체를 삭제하는 가장 좋은 방법은 무엇입니까? 부모를 삭제하지 않습니다. 내 부모 개체에는 자식 개체의 IList가 포함되어 있습니다. 다음은 일대 다 관계에 대한 매핑입니다.

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

clear ()를 사용하여 컬렉션에서 모든 개체를 제거한 다음 SaveOrUpdate ()를 호출하면 다음 예외가 발생합니다.

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

자식 개체를 개별적으로 삭제 한 다음 부모에서 제거하려고하면 예외가 발생합니다.

deleted object would be re-saved by cascade

NHibernate에서 자식 개체를 삭제하는 것은 이번이 처음입니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

편집 : 명확히하기 위해-부모 개체를 삭제하려는 것이 아니라 자식 개체 만 삭제하려고합니다. 나는 부모의 일대 다 관계를 설정했습니다. 하위 개체 매핑에 대해 다 대일 관계도 만들어야합니까?

답변:


139

컬렉션에서 항목을 제거 할 때 NHibernate의 기본 작동 모드는 단순히 연결을 끊는 것이기 때문에 첫 번째 오류가 발생합니다. 데이터베이스에서 NHibernate는 자식 행의 외래 키 열을 null로 설정하려고합니다. 해당 열에 null을 허용하지 않기 때문에 SQL Server에서 오류가 발생합니다. 컬렉션을 지운다 고해서 반드시 자식 개체가 삭제되는 것은 아니지만이를 수행하는 한 가지 방법은 cascade = all-delete-orphan을 설정하는 것입니다. 이는 NHibernate에게 외래 키 열을 설정하는 대신 새로 분리 된 행을 삭제해야 함을 알려줍니다.

SaveOrUpdate NHibernate를 호출하면 먼저 모든 자식 개체를 삭제하기 때문에 두 번째 오류가 발생합니다. 그런 다음 어느 관계도 역으로 표시되지 않기 때문에 NHibernate는 자식 테이블의 외래 키 열을 null로 설정하려고 시도합니다. 행이 이미 삭제되었으므로 두 번째 오류가 발생합니다. 이 문제를 해결하려면 관계의 한쪽에 inverse = true를 설정해야합니다. 이는 일반적으로 하나 (기본 키 또는 상위) 측에서 수행됩니다. 이렇게하지 않으면 NHibernate가 관계의 각 측면에 대해 적절한 업데이트를 수행합니다. 불행히도 두 개의 업데이트를 실행하는 것은 적절한 작업이 아닙니다.

관계의 한 쪽을 항상 반대쪽으로 표시해야합니다. 코딩 방법에 따라 계단식을 사용해야 할 수도 있고 필요하지 않을 수도 있습니다. Clear ()를 사용하여 원샷 삭제를 활용하려면 캐스케이드를 정의해야합니다.


명확히하기 위해-지금은 Parent 개체에 정의 된 관계 만 있습니다. 두 번 모두 동일한 결과로 해당 개체의 캐스케이드를 "all"및 "all-delete-orphan"으로 설정하려고했습니다. 자식 개체에 대해서도 다 대일 관계를 정의해야한다는 뜻입니까?
Mark Struzinski

이 경우 inverse = "true"가 부모 또는 자식 개체에 속합니까?
Mark Struzinski

3
외래 키를 보유하지 않는 클래스에 속합니다. 일반적으로 부모입니다.
pmlarocque

이 설명을 해주셔서 다시 한 번 역 문제가 저를 잡았고, 이렇게 설명하는 것이 정말 도움이되었습니다.
Mark Dickinson

이것은 제가 겪고있는 문제를 해결하는 데 정말 도움이되었습니다. 감사.
Robin Robinson

3

Chuck의 답변에 따르면 부모 측 매핑에 Inverse = true를 추가하여 문제를 해결했습니다.

메시지에 많은 MessageSentTo가 있습니다.

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

Castle ActiveRecord를 사용하고 있습니다. 척 감사합니다.


2

saveOrUpdate () 대신 merge ()를 사용해보십시오. 또한 캐스케이드가 all-delete-orphan으로 설정되어 있고 부모-자식 관계가 반전 가능한지 확인하십시오 (부모에서 inverse = true이고 not-null = true 인 부모 ID 인 자식의 필드). .


2

이 예에는 제품이 nullable이 아닌 많은 제품이있는 카테고리가 있습니다.

플러시 전에 제품을 삭제하고 상위 컬렉션에서 제거하여 문제를 해결할 수 있지만 더 나은 해결책을 찾고 있습니다.

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

어쨌든 도움이되기를 바랍니다.


1
그래도 다른 저장소가 필요합니다.
UpTheCreek

0

계단식 속성 값을 "all"에서 "all-delete-orphan"으로 변경합니다.


이것을 시도했습니다. 여전히 동일한 예외가 발생합니다.
Mark Struzinski

16
all-delete-orphan은 상위를 삭제할 때 하위를 삭제합니다. 이 사람이 묻는 것처럼 아이들을 삭제하는 것과는 아무 관련이 없습니다.
Kyle West

-3

문제를 일으키는 열의 매핑에서 Not-Null = true를 설정하십시오. 그래도 정확한 구문이 확실하지 않습니다 (죄송합니다).


좋아, 자식 개체의 매핑에서 열을 not-null = "true"로 설정했습니다. 따라서 자식 개체의 IList에서 clear () 메서드를 호출 한 다음 SaveOrUpdate ()를 시도합니다. 여전히 "NULL 값을 열에 삽입 할 수 없습니다"오류가 발생합니다. 내가 다른 일을 잘못하고 있습니까?
Mark Struzinski

오류가 발생한 열은 무엇입니까? 모델의 하위 항목을 정확히 얼마나 삭제하고 있습니까?
Kyle West

부모 개체의 Ilist 자식 개체에 대해 clear () 메서드를 호출하고 있습니다. 그런 다음 부모에서 SaveOrUpdate ()를 호출합니다.
Mark Struzinski
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.