2009-03-14 17 views
10

Mô hình miền mà tôi đang làm việc trên đó có các thực thể tổng hợp và con gốc. Nội dung nào đó giống như mã sau:Thực tiễn tốt nhất cho các danh sách chỉ đọc trong NHibernate

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

class OrderLine 
{ 
} 

Bây giờ tôi muốn Đơn đặt hàng của mình kiểm soát các dòng. Một cái gì đó như thế:

class Order 
{ 
    OrderLine[] Lines {get;} 

    void AddLine(OrderLine line); 
} 

Tại thời điểm này chúng tôi đang sử dụng mô hình sau:

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

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

NHibernate là ánh xạ trực tiếp đến lĩnh vực dòng.

Bây giờ câu hỏi ...

  • để bạn thực hành gì trong những tình huống như vậy?
  • Có ai sử dụng phương pháp: Số lượt truy cập công khai trên IE()
  • Bạn đang sử dụng làm loại trả lại cho thuộc tính? Có thể là ReadOnlyCollection hoặc IEnumerable;
  • Có thể đây không phải là nơi tốt nhất để hỏi? Đề nghị xin vui lòng.

Cập nhật: Có vẻ chiến thắng IEnumerable, tuy nhiên giải pháp vẫn chưa hoàn hảo ...

Trả lời

9

Các mô hình tôi sử dụng là:

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

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

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

Nếu bạn đang sử dụng NET 3.5 bạn sẽ có được tất cả các tìm kiếm chức năng mà bạn có thể muốn cho IEnumerable bằng LINQ và bạn ẩn việc triển khai bộ sưu tập của mình.

Vấn đề với trở Hang [] là bộ sưu tập của bạn có thể được sửa đổi từ bên ngoài ví dụ:

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

Về "Order.Lines [0] = Hang mới();" nó không thể. Mỗi lần bạn truy cập vào bản sao Lines mới của mảng được phát hành (tôi không thích điều này mặc dù ...). IEnumerable có thiếu chức năng danh sách, tôi có nghĩa là Đếm, truy cập theo chỉ mục. Tất nhiên, LINQ bao gồm điều này. Cảm ơn bạn! –

+0

Tại đây, bạn vẫn có thể truyền thuộc tính Đường dây thành Danh sách và sửa đổi bộ sưu tập theo cách đó ... –

+2

Có, nhưng bạn phải thực hiện quá trình truyền. Nó không phải là quá nhiều về bảo vệ nhưng về việc hiển thị những gì bạn được phép làm cho bộ sưu tập. Bạn có thể trả lại this.lines.AsReadonly() nếu bạn muốn bảo mật bổ sung đó. – gcores

3

tôi phơi bày bộ sưu tập như ReadOnlyCollection và sử dụng AddX và RemoveX phương pháp để duy trì các bộ sưu tập. Chúng tôi chỉ chuyển sang 3.5 và tôi đang suy nghĩ về việc hiển thị IEnumerable. Trong hầu hết các trường hợp với NHibernate đứa trẻ có một tham chiếu đến phụ huynh để lộ Add và Remove phương pháp cho phép bạn duy trì mối quan hệ đó:

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, có vẻ như IEnumerable Beats ReadOnlyCollection ... ReadOnlyCollection khiến API khó hiểu. Nó vẫn có thêm phương pháp sẽ ném ngoại lệ trong thời gian chạy ... –

+1

Mike - Tôi nghĩ rằng bạn đang nhầm lẫn về điều này. Trả về một Danh sách .AsReadOnly() không hiển thị phương thức Thêm nhưng ReadOnlyCollection thì không. ReadOnlyCollection nằm trong System.Collections.ObjectModel nên nó thường bị bỏ qua. –

+0

Hài hước, đúng vậy ..Tôi đã bỏ qua nó. Cảm ơn nhiều. –

1

Nếu tôi phơi bày một danh sách mà không nên được sửa đổi, sau đó tôi sử dụng IEnumerable và năng suất. Tôi tìm thấy nó cồng kềnh cố gắng sử dụng ReadOnlyCollections kết hợp với NHiberante.

Với cách tiếp cận này, bạn vẫn có trường đường riêng được lập bản đồ và điền thông qua NHibernate; tuy nhiên, truy cập công khai vào bộ sưu tập được thực hiện thông qua các trình lặp. Bạn không thể thêm vào hoặc loại bỏ khỏi danh sách cơ bản với thuộc tính Lines này.

Ví dụ:

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

Tại sao không chỉ "trả lại đường"? Bạn đang bảo vệ khỏi việc truyền? Giải pháp với sản lượng có nghĩa là Count() sẽ yêu cầu foreach và sẽ tải tất cả các ites được hỗ trợ (trong trường hợp tải lười). –

+0

Các IEnumerable kết hợp với năng suất cho phép bạn đi bộ sưu tập mà không có thể thêm/loại bỏ các mục. –

+0

Vâng, tất cả IEnumerable của chính nó cũng sẽ ngăn cản bạn thêm/loại bỏ các mục - do đó, một public IEnumerable Lines {get {return lines; }} 'là đủ. – Dav

14

tôi làm điều đó như thế này:

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

Sau đó, dĩ nhiên, trong các bản đồ, NHibernate là nói để sử dụng _orderLines lĩnh vực:

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

Với mã của bạn, mã sau sẽ không thành công: order.OrderLines! = Order.OrderLines; Tôi không chắc chắn nếu điều này là xấu hay không ... Dù sao cảm ơn bạn. –

+0

Điều đó không quan trọng, vì bạn không nên so sánh nó theo cách đó :) –

+0

Giải pháp tốt. Điều này đã giúp tôi rất nhiều. Cảm ơn! – CalebHC

0

Tôi đã dành vài ngày để tìm cách tiếp cận tốt nhất cho các danh sách chỉ đọc trong NHibernate. Cuộc thảo luận này đã giúp tôi rất nhiều để hình thành một dự án phù hợp với dự án của chúng tôi.

Có một cách tiếp cận tôi bắt đầu sử dụng:

  1. lĩnh vực Backing được sử dụng để lưu trữ các bộ sưu tập
  2. IEnumerable < T> được sử dụng để phơi bày các bộ sưu tập để buộc khách hàng sử dụng AddLine() và RemoveLine phương pháp() .
  3. ReadOnlyCollection type được sử dụng ngoài IEnumerable.

Code:

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; } 
} 
Các vấn đề liên quan