2012-01-27 3 views
2

NHibernate를 통해 컬렉션을 검색 할 때 .RemoveAll을 사용할 수 없다는 문제가 있습니다.NHibernate : 컬렉션에서 .RemoveAll 호출하기

NHibernate를 통해 지속되는 Order이라는 엔티티가 있습니다.

Order은 많은 OrderItems입니다. 다음과 같이 내 도메인에서

mapping.HasMany(o => o.Items) 
        .Cascade.AllDeleteOrphan() 
        .AsList() 
        .Inverse(); 

: 다음은이 관계에 대한 내 매핑은

public virtual IList<OrderItem> Items { get; set; } 

내가 알고있는 것처럼, 내가 NHibernate에이 목록의 자신의 구현입니다 때문에 IList을 사용해야합니다.

지금 내 Order 클래스에이 방법을 사용하여 내 Order에서 항목을 제거하려면 :

public virtual void RemoveItem(string variantSku) 
{ 
    items.RemoveAll(x => x.Variant.VariantSku == variantSku); 
} 

그것은 작동하지 않습니다, IList이 방법이 없기 때문에.

items.ToList().RemoveAll(x => x.Variant.VariantSku == variantSku); 

을하지만 그것은 작동하지 않습니다

나는 시도했다. 나는 items.ToList() 실제로 원래 목록의 복사본을 생성 실현, 그래서 내가 시도 할 수 같아요

var itemsList = items.ToList(); 
itemsList.RemoveAll(...) 

하지만 여전히 NHibernate에를 통해 지속 하는가?

내 질문 :이 문맥에서 실제로 .RemoveAll을 사용할 수 있습니까? 아니면 다른 방법으로 항목을 제거해야합니까?

답변

4

콜렉션을 관계의 반대쪽으로 맵핑 했으므로 콜렉션에서 항목을 제거하는 것 이외에 OrderItem 측에서 순서에 대한 참조를 무효화해야합니다. 따라서 RemoveAll 메서드 또는 확장 메서드는 작업을 수행하지 않습니다.

나는 이런 식으로 처리 할 것 :

public virtual void RemoveItem(string variantSku) 
{ 
    var itemsToRemove = items.Where(x => x.Variant.VariantSku == variantSku).ToArray(); 
    foreach(var item in itemsToRemove) 
    { 
     item.Order = null; 
     items.Remove(item); 
    } 
} 

나는 대신 가방 매핑 세트 사용하는 것이 좋습니다.

+0

매핑이 .ascest.AllDeleteOrphan() 인 경우 item.Order = null이 필요한지 잘 모르겠습니다. AllDeleteOrphan()이하는 일이 아닙니까? 나머지는 그 자리에 있습니다. 항목을 foreach'ing하고 제거하려고하는 모범생 실수하고 있었다. – autonomatt

+0

item.Order = null은이를 고아로 만드는 요소이며, 그렇지 않으면 세션을 플러시 할 때 다시 저장됩니다. –

+0

실제로 코드가 작동하지 않습니다. 여전히 예외가 발생합니다. "컬렉션이 수정되었습니다. 열거 연산이 실행되지 않을 수 있습니다. "for 루프를 사용하여 종료되었습니다. – autonomatt

3

당신은 항상 당신의 자신의 RemoveAll 확장 메서드를 만들 수 있습니다 내가 NHibernate에 컬렉션 자체에 대한 관심을 기대

public static void RemoveAll<T>(this IList<T> source, Predicate<T> predicate) 
{ 
    // TODO: Argument non-nullity validation 

    // Optimization 
    List<T> list = source as List<T> 
    if (list != null) 
    { 
     list.RemoveAll(predicate); 
     return; 
    } 

    // Slow way 
    for (int i = source.Count - 1; i >= 0; i--) 
    { 
     if (predicate(source[i])) 
     { 
      source.RemoveAt(i); 
     } 
    } 
} 

을 - 단지 List<T>에서 항목을 제거하는 것은 NHibernate에 할 수있는 "통지 일이 아니다 ".

물론 NHibernate가 당신이하는 일에 신경 쓰고 싶지 않다면 - 변경 사항이 인 경우에만이 로컬 일 것임을 의미합니다. 그렇다면 최종 코드는 괜찮을 것입니다.

+0

아하, "C#"태그는 위대한 Jon Skeet을 소개합니다. 스택 마스터입니다. 알고 싶습니다. :) ... 나는이 작업에 신경을 쓰려면 NHibernate가 필요합니다. – autonomatt

+0

@autonomatt : 반환 된 콜렉션이'RemoveAt'를 사용하여 항목을 제거하게되어 있다고 가정 할 때, 이것은 괜찮을 것입니다. –

관련 문제