2009-03-14 3 views
10

현재 작업하고있는 도메인 모델에는 루트 집계 및 하위 엔티티가 있습니다. 다음 코드와 같은 뭔가 : NHibernate에서 읽기 전용 목록에 대한 가장 좋은 방법은 무엇입니까

class Order 
{ 
    IList<OrderLine> Lines {get;set;} 
} 

class OrderLine 
{ 
} 

지금 내가 원하는 라인을 제어하기 위해 내 주문하기. 뭐 그런 : NHibernate에이 라인 필드에 직접 매핑됩니다

class Order 
{ 
    private IList<OrderLine> lines = new List<OrderLine>(); 
    OrderLine[] Lines {get {return this.lines;}} 

    void AddLine(OrderLine line) 
    { 
     this.orders.Add(line); 
    { 
} 

:

class Order 
{ 
    OrderLine[] Lines {get;} 

    void AddLine(OrderLine line); 
} 

이 시점에서 우리는 다음과 같은 패턴을 사용하고 있습니다. 이제

질문 ... 당신이 그런 상황에서 무엇을 연습 할

  • ?
  • 방법을 사용하는 사람 : 공개 IEnumerable GetLines()
  • 속성의 반환 형식으로 무엇을 사용하고 있습니까? ReadOnlyCollection 또는 IEnumerable 일 수 있습니다.
  • 이것이 최고의 장소가 아닐 수도 있습니다. 제발 제안 해.

업데이트 : 당신은 NET 3.5을 사용하는 경우

class Order 
{ 
    private List<OrderLine> lines = new List<OrderLine>(); 

    IEnumerable<OrderLine> Lines { get { return this.lines; } } 

    void AddLine(OrderLine line) 
    { 
     this.orders.Add(line); 
    } 
} 

모든 검색을 얻을 : 내가 사용하는 패턴은

답변

9

... 그러나 해결책은 아직 완벽하지 않습니다, IEnumerable을 승리 보인다 기능은 LINQ를 사용하여 IEnumerable에 대해 원하는 기능을 제공하며 컬렉션 구현을 숨길 수 있습니다.

OrderLine에 [] 복귀 문제는 컬렉션 외부 예 수정 될 수 있다는 것이다 :

Order.Lines[0] = new OrderLine(). 
+0

대해서는 "Order.Lines [0] 새를 OrderLine에() =;" 그럴 순 없어. 라인에 접근 할 때마다 배열의 새로운 사본이 발행됩니다 (나는 이것을 좋아하지 않습니다 ...). IEnumerable에는 목록 기능이 부족합니다. 즉, 인덱스에 의한 액세스를 의미합니다. 물론 LINQ가이를 다룹니다. 감사합니다. –

+0

여기에서 Lines 속성을 목록으로 캐스팅하고 그런 식으로 컬렉션을 수정할 수 있습니다. –

+2

예,하지만 캐스팅을해야합니다. 보호에 관한 것이 아니라 컬렉션에 허용 된 것을 보여주는 것입니다. 여분의 보안을 원할 경우 this.lines.AsReadonly()를 반환 할 수 있습니다. – gcores

3

난 ReadOnlyCollection로 컬렉션을 노출과 모음을 유지 AddX 및 RemoveX 방법을 사용한다. 방금 3.5로 전환했고 IEnumerable을 대신 노출하려고합니다. 그때 사용, 내가 수정할 수 없습니다 목록을 노출하고있어 경우

public void AddPlayer(Player player) 
    { 
     player.Company = this; 
     this._Players.Add(player); 
    } 

    public void RemovePlayer(Player player) 
    { 
     player.Company = null; 
     this._Players.Remove(player); 
    } 
+0

예, IEnumerable이 ReadOnlyCollection을 상회하는 것 같습니다. ReadOnlyCollection은 API를 혼동스럽게 만듭니다. 그것은 여전히 ​​런타임에 예외를 던질 Add 메서드를 ... –

+1

마이크 - 나는 당신이 이것에 착각 한 것 같아요. 목록 반환 .AsReadOnly()는 Add 메서드를 노출하지만 ReadOnlyCollection 은 노출하지 않습니다. ReadOnlyCollection 은 종종 간과되기 때문에 System.Collections.ObjectModel에 있습니다. –

+0

재밌 네요, 그래 그게 사실이야 ..나는 그것을 간과했다. 고맙습니다. –

1

: NHibernate에 대부분의 경우에 아이는 당신이 그 관계를 유지할 수 있도록 추가 방법을 제거 노출 부모에 대한 참조가 IEnumerable 및 yield. NHiberante와 함께 ReadOnlyCollections를 사용하는 것이 번거로울 때가 있습니다.

이 방법을 사용하면 여전히 NHibernate를 통해 매핑되고 채워지는 전용 회선 필드가 있습니다. 그러나 컬렉션에 대한 공용 액세스는 반복자를 통해 수행됩니다. 이 Lines 속성을 사용하여 기본 목록에 추가하거나 목록에서 제거 할 수 없습니다.

예를 들어

:

public IEnumerable<OrderLine> Lines { 
    get { 
     foreach (OrderLine aline in lines) { 
      yield return aline; 
     } 
    } 
} 
+0

왜 "회선 복귀"하지 않습니까? 캐스팅을 보호하고 있습니까? yield를 사용하는 솔루션은 Count()가 foreach를 요구하고 모든 지연된 ites를로드합니다 (지연로드의 경우). –

+0

yield와 결합 된 IEnumerable을 사용하면 항목을 추가/제거하지 않고 컬렉션을 이동할 수 있습니다. –

+0

글쎄요, IEnumerable 모두 자체적으로 항목 추가/제거를 막을 수 있습니다. - 그래서'public IEnumerable Lines {get {return lines; }}'충분해야합니다. – Dav

14

나는 이런 식으로 작업을 수행합니다

public class Order 
{ 
     private ISet<OrderLine> _orderLines = new HashedSet<OrderLine>(); 

     public ReadOnlyCollection<OrderLine> OrderLines 
     { 
      get { return new List<OrderLine>(_orderLines).AsReadOnly(); } 
     } 

     public void AddOrderLine(OrderLine ol) 
     { 
      ... 
     } 
} 

그런 다음, offcourse, 매핑에서, NHibernate에이 _orderLines 필드 사용하라고 :

<set name="OrderLine" access="field.camelcase-underscore" ... > 
... 
</set> 
+0

다음 코드를 사용하면 코드가 실패합니다 : order.OrderLines! order.OrderLines; 이것이 나쁜지 확실하지 않은 경우 ... 어쨌든 고맙습니다. –

+0

그 방법은 그것을 비교해서는 안되기 때문에 그건 중요하지 않습니다 :) –

+0

좋은 해결책. 이것은 나를 많이 도와 줬다. 감사! – CalebHC

0

NHibernate에서 읽기 전용리스트를위한 최선의 접근법을 찾기 위해 며칠을 보냈다. 이 토론은 우리 프로젝트에 맞는 양식을 만드는 데 많은 도움이되었습니다.

  1. 백업 필드를 저장하는 컬렉션
  2. 를 IEnumerable < T>를 사용하는 데 사용하는 클라이언트를 강제로 컬렉션을 AddLine()와 RemoveLine() 메소드를 사용 노출 :

    내가 사용하기 시작 접근 방식이있다 .

  3. ReadOnlyCollection 형식이 IEnumerable과 함께 사용됩니다.

번호 :

public class Order 
{ 
    private readonly IList<OrderLine> lines = new List<OrderLine>(); 

    public virtual IEnumerable<OrderLine> Lines 
    { 
     get 
     { 
      return new ReadOnlyCollection<OrderLine>(lines); 
     } 
    } 

    public void AddLine(OrderLine line) 
    { 
     if (!lines.Contains(line)) 
     { 
      this.lines.Add(line); 
      line.Order = this; 
     } 
    } 

    public void RemoveLine(OrderLine line) 
    { 
     if (lines.Contains(line)) 
     { 
      this.lines.Remove(line); 
      line.Order = null; 
     } 
    } 
} 

public class OrderLine 
{ 
    public Order Order { get; set; } 
}