2009-03-14 11 views
10

Etki Alanı Modeli için en iyi uygulama nedir? Kök agregası ve alt öğeleri var. Aşağıdaki kodu gibi şey: Şu an üzerinde çalıştığım NHibernate

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

class OrderLine 
{ 
} 

Şimdi istediğim satırları kontrol etme Sipariş. Bunun gibi bir şey: NHibernate hatları alanına doğrudan eşleştirilmiş

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); 
} 

Şu an için aşağıdaki deseni kullanıyor. Şimdi

sorular ... Böyle durumlarda ne uyguluyorsunuz

  • ?
  • Herhangi biri şu yöntemleri kullanır: public IEnumerable GetLines()
  • Özellik için ne tür bir özellik kullanıyorsunuz? ReadOnlyCollection veya IEnumerable olabilir;
  • Sormak için en iyi yer burası olmayabilir mi? Lütfen öner.

Güncelleme: NET 3.5 kullanıyorsanız

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

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

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

tüm arama olsun: Kullandığım kalıptır

cevap

9

... Ancak çözüm hala mükemmel değil, IEnumerable kazanır görünüyor LINQ kullanarak IEnumerable için istediğiniz işlevsellik ve toplama uygulamanızı gizlersiniz.

Sipariş Hattı [] dönen sorun koleksiyonunuzu dışarıdan mesela değiştirilebilir olmasıdır:

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

ilişkin "Order.Lines [0] yeni sipariş satırı() =;" olamaz. Verilen dizinin Çizginin yeni kopyasına her eriştiğinizde (bundan hoşlanmıyorum ...). IEnumerable, liste işlevsellik eksikliği var, ben saymak, endeks ile erişim anlamına gelir. Tabii ki, LINQ bunu kapsar. Teşekkür ederiz! –

+0

Burada, Lines özelliğini bir Listesine yayınlayabilir ve koleksiyonu bu şekilde değiştirebilirsiniz ... –

+2

Evet, ancak döküm işlemini yapmanız gerekir. Korumayla ilgili değil, koleksiyona yapmanıza izin verdiğinizi göstermekle ilgili. Bu ekstra güvenlik istiyorsanız, this.lines.AsReadonly() öğesini geri yükleyebilirsiniz. – gcores

3

Ben ReadOnlyCollection olarak koleksiyonlarını teşhir ve koleksiyonlarını korumak için AddX ve RemovEx yöntemleri kullanın. Sadece 3.5'e geçtik ve bunun yerine IEnumerable'ı göstermeyi düşünüyorum. Sonra kullandığım, ben değiştirilmemelidir bir liste açığa olsam

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

Yeh, IEnumerable beats ReadOnlyCollection ... ReadOnlyCollection API kafa karıştırıcı yapar. Hala çalışma zamanında istisna atacak Add yöntemi var ... –

+1

Mike - Ben bunun üzerinde yanlış olduğunu düşünüyorum. Bir Listenin Dönülmesi .AsReadOnly() bir Add yöntemini ortaya çıkarır ancak ReadOnlyCollection yapmaz. ReadOnlyCollection System.Collections.ObjectModel içinde olduğundan, genellikle göz ardı edilir. –

+0

Komik, evet bu doğru ..Onu gözden kaçırdım. Çok teşekkür ederim. –

1

: NHibernate ile Çoğu durumda çocuk bu ilişkiyi sürdürmek için izin verir, böylece ekleyin ve yöntemleri çıkarmak açığa ebeveyn bir referansı vardır IEnumerable ve verim. Ben NHIBerante ile birlikte ReadOnlyCollections kullanmaya çalışıyorum hantal bulabilirsiniz.

Bu yaklaşımla, hala NHibernate üzerinden eşlenen ve listelenen özel çizgiler alanınız var; Ancak, koleksiyona kamu erişimi yineleyiciler üzerinden gerçekleştirilir. Bu Satırlar özelliğiyle temel listeye eklenemez veya bu listeden kaldırılamaz.

Örneğin

:

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

Neden sadece "satırları döndür" değil? Dökümden koruyor musun? Verim ile çözüm, Count() 'ın foreach gerektireceği ve tüm yedeklenmiş yükleri (tembel yük durumunda) yükleyeceği anlamına gelir. –

+0

Verim ile birleştirilen IEnumerable, öğeleri ekleyemeden/çıkarmadan koleksiyonda yürümenizi sağlar. –

+0

Eh, IEnumerable tek başına öğeleri eklemenizi/çıkarmanızı da engeller - böylece bir "public IEnumerable Lines {get {return lines; }} 'yeterli olmalıdır. – Dav

14

ben böyle yapmak:

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) 
     { 
      ... 
     } 
} 

Sonra offcourse, haritalama içinde NHibernate _orderLines alanını kullanmaya anlatılıyor:

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

Kodunuz aşağıdaki kod ile başarısız olur: order.OrderLines! = Order.OrderLines; Bunun kötü olup olmadığından emin değilim ... Neyse, teşekkür ederim. –

+0

Bu imho farketmez, çünkü bu şekilde karşılaştırmamalısınız :) –

+0

İyi bir çözüm. Bu bana çok yardımcı oldu. Teşekkürler! – CalebHC

0

NHibernate'deki readonly listeleri için en iyi yaklaşımı arayan birkaç gün geçirdim. Bu tartışma projemize uygun olanı oluşturmamda bana çok yardımcı oldu.

  1. Taban alanları mağaza koleksiyonları
  2. IEnumerable < T> kullanılır için kullanılır müşterilerine zorlamak için koleksiyonları AddLine() ve RemoveLine() kullanın yöntemleri ortaya çıkarmak için:

    ben kullanmaya başladım bir yaklaşım vardır .

  3. ReadOnlyKoleksiyon türü, IEnumerable'a ek olarak kullanılır.

Kodu:

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