关于.net:NHibernate中只读列表的最佳实践是什么

What is the best practice for readonly lists in NHibernate

我正在处理的域模型具有根聚合和子实体。类似下面的代码:

1
2
3
4
5
6
7
8
class Order
{
   IList<OrderLine> Lines {get;set;}
}

class OrderLine
{
}

现在我要我的订单控制线路。就像这样:

1
2
3
4
5
6
class Order
{
   OrderLine[] Lines {get;}

   void AddLine(OrderLine line);
}

此时,我们使用以下模式:

1
2
3
4
5
6
7
8
9
10
class Order
{
   private IList<OrderLine> lines = new List<OrderLine>();
   OrderLine[] Lines {get {return this.lines;}}

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

nHibernate直接映射到Lines字段。

现在有问题…

  • 你在这种情况下做什么练习?
  • 是否有人使用以下方法:公共IEnumerable GetLines()。
  • 您使用什么作为属性的返回类型?可以是ReadOnlyCollection或IEnumerable;
  • 请问这不是最好的地方吗?请建议。

更新:似乎IEnumerable获胜,但解决方案仍然不完美…


我是这样做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
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 )
      {
          ...
      }
}

然后,当然,在映射中,nhibernate被告知使用"orderlines"字段:

1
2
3
<set name="OrderLine" access="field.camelcase-underscore" ... >
...
</set>


我使用的模式是:

1
2
3
4
5
6
7
8
9
10
11
class Order
{
   private List<OrderLine> lines = new List<OrderLine>();

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

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

如果您使用的是NET 3.5,那么您可以使用LINQ获得IEnumerable所需的所有搜索功能,并隐藏集合实现。

返回orderline[]的问题是可以从外部修改集合,例如:

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


我将集合公开为readOnlyCollection,并使用addx和removex方法来维护集合。我们刚切换到3.5,我想改为公开IEnumerable。在大多数情况下,使用NHiberinate时,孩子会引用父母,因此暴露添加和删除方法可以让您保持这种关系:

1
2
3
4
5
6
7
8
9
10
11
    public void AddPlayer(Player player)
    {
        player.Company = this;
        this._Players.Add(player);
    }

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


如果我要公开一个不应该修改的列表,那么我将使用IEnumerable和yield。我觉得把读出器集合与nhibrante结合使用很麻烦。

使用这种方法,您仍然可以使用private lines字段,该字段通过nhibernate进行映射和填充;但是,对集合的公共访问是通过迭代器执行的。不能使用此行属性添加到基础列表或从基础列表中删除。

例如:

1
2
3
4
5
6
7
public IEnumerable<OrderLine> Lines {
    get {
        foreach (OrderLine aline in lines) {
            yield return aline;
        }
    }
}


我花了几天时间寻找一种在nhibernate中查找只读列表的最佳方法。这个讨论帮助我形成了一个适合我们项目的讨论。

我开始使用一种方法:

  • 支持字段用于存储集合
  • IEnumerable用于公开集合以强制客户端使用addline()和removeline()方法。
  • 除了IEnumerable之外,还使用了readOnlyCollection类型。
  • 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    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; }
    }