2010-02-16 7 views
5

두 개체 (부모 및 자식)간에 부모 자식 관계가 있습니다. 다음과 같이컬렉션에서 항목 제거 (NHibernate)

내 부모 매핑은 다음과 같습니다

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

나는 다음과 같은 실행하고 싶습니다 :

someParent.Children.Remove(someChild); 

자식 클래스는 유형, 다른 부모 클래스에 대한 참조를 가지고있다. 관계는

relation diagram

같은 주를 보이는 : 나는 위의 링크되지 않은 URL에 대한 사과, 나는이 때문에 마크 업

을 사용하여 URL 문자열에 별표 (*)를지나 얻을 수가 없습니다 관계에서 위 코드를 호출하면 DELETE 쿼리 대신 Child 테이블에서 ParentID를 제거하는 UPDATE 쿼리가 생성됩니다 (null로 설정).

Parent.Children 컬렉션에서 제거 할 때 NHibernate가 하위 레코드를 완전히 삭제하도록 할 수 있습니까?

UPDATE 스펜서의 솔루션

아주 매력적 솔루션 @

이 미래의 클래스에서 구현 될 수있는 무언가가있다. 그러나 저장소 패턴에서 세션이 처리되는 방식 (특정 경우)으로 인해 응용 프로그램에 따라 세션 유형 (CallSessionContext/WebSessionContext)을 전달해야하므로 불가능합니다.

제이미의 솔루션

간단하고 신속하게 실행할 수 그러나 내가 공격 한 다른 도로 블록 @. 내 자식 엔티티는 다음과 같습니다 : entity object

새 메서드를 사용하는 경우 NHibernate는 단일 삭제 outright가 아닌 TypeID 및 ParentID를 null로 설정하는 업데이트 명령문을 생성합니다. 구현 내에서 무언가를 놓친 경우이 방법을 사용하면 앞으로 나아갈 수 있습니다.

@The One-Shot-Delete solution described here은 단일 삭제를 강제 실행하기 위해 컬렉션을 역 참조하는 아이디어를 개략적으로 설명합니다. 위와 같은 결과이지만 업데이트 문이 발행됩니다.

//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; 

솔루션 파고의 조금 걸렸지 만 제이미의 솔루션은 몇 가지 추가 수정을 통해왔다. = 역은 = 사실, 캐스케이드 모든

부모 매핑 - - 역은 = 사실, 계단식 = 모두 삭제 - 고아

이 같은 방법으로 제거를

유형 매핑 : 미래의 독자를 들어, 위 내 수업 모델을 기반으로 Jamie의 솔루션 작업에 설명되어 있습니다.분리 된 항목 당 하나의 delete 문이 생성되므로 나중에 튜닝 할 가능성이 있지만 최종 결과는 성공적입니다.

답변

1

, 방법을 통해 컬렉션에 대한 액세스를 제어 RemoveChild 메서드.

0

하이버 네이트는 레코드가 고아인지 알 수없는 방법이기 때문에 이것은 정확하게 가능하지 않다고 생각합니다. 다른 클래스가 자식 클래스와 관련이 있는지를 확인할 수 있지만, 그렇지 않을 수도있는 전체 DB 구조를 알고 있다고 가정합니다.

당신은 완전히 운이 좋지는 않습니다. 사용자 지정 ICascadeDeleteChild 인터페이스와 함께 IList 인터페이스를 사용하면 훨씬 매끄러운 솔루션을 만들 수 있습니다. 다음은 기본 단계입니다.

  1. IList와 IList 인 <>이 속하는 클래스를 만들고이를 CascadeDeleteList 또는 그 라인을 따라 호출하십시오.
  2. 이 클래스 내부에 개인 .Net List를 만들고이 목록에 다양한 메소드 호출을 프록시하기 만하면됩니다.
  3. ICascadeDeleteChild라는 인터페이스를 만들고 메서드를 제공하십시오. Delete()
  4. CascadeDeleteList의 Delete 메서드에서 삭제할 개체 유형을 확인하십시오. ICascadeDeleteChild 유형이면 Delete 메서드를 호출하십시오.
  5. ICascadeDeleteChild 인터페이스를 구현하도록 Child 클래스를 변경하십시오.

나는 고통스러워 보일지 모르지만 일단 이러한 인터페이스가 수행되면 주변을 포위하는 것이 간단해야합니다.

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

Type.RemoveChild이 비슷하게하지만 당신은 서로의 전화 무한 루프에 넣지 않도록주의 할 것 : 대신 IList<Child> 노출의

+0

나는 올바른 경로로 나를 몰아 붙였을 것이라고 믿는다. 저장소 블록 (저장소 패턴에서이를 설정한다. (이 경우 자식 Delete 메서드는 자체 저장소 메서드를 호출한다)을 사용할 수있다. 이것은 다른 세션 컨텍스트 (즉, CallSessionContext와 WebSessionContext) –

관련 문제