.net NHibernate中只读列表的最佳实践是什么
我正在处理的域模型具有根聚合和子实体。 类似于以下代码:.net NHibernate中只读列表的最佳实践是什么,.net,arrays,nhibernate,list,domain-driven-design,.net,Arrays,Nhibernate,List,Domain Driven Design,我正在处理的域模型具有根聚合和子实体。 类似于以下代码: class Order { IList<OrderLine> Lines {get;set;} } class OrderLine { } 目前,我们正在使用以下模式: class Order { private IList<OrderLine> lines = new List<OrderLine>(); OrderLine[] Lines {get {return this.l
class Order
{
IList<OrderLine> Lines {get;set;}
}
class OrderLine
{
}
目前,我们正在使用以下模式:
class Order
{
private IList<OrderLine> lines = new List<OrderLine>();
OrderLine[] Lines {get {return this.lines;}}
void AddLine(OrderLine line)
{
this.orders.Add(line);
{
}
类顺序
{
私有IList行=新列表();
OrderLine[]行{get{返回this.Lines;}}
无效添加行(订单行)
{
此.orders.Add(行);
{
}
NHibernate直接映射到lines字段
现在问题
- 在这种情况下你会做什么
- 是否有人使用以下方法: 公共IEnumerable GetLines()
- 您使用什么作为属性的返回类型?可以是ReadOnlyCollection或IEnumerable
- 也许这不是最好的提问地点?请建议
class Order
{
private List<OrderLine> lines = new List<OrderLine>();
IEnumerable<OrderLine> Lines { get { return this.lines; } }
void AddLine(OrderLine line)
{
this.orders.Add(line);
}
}
我将集合公开为ReadOnlyCollection,并使用AddX和RemoveX方法来维护集合。我们刚刚切换到3.5,我正在考虑公开IEnumerable。在大多数情况下,使用NHibernate时,子对象引用父对象,因此公开Add和RemoveX方法可以让您维护这种关系:
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。我发现将ReadOnlyCollections与NHiberante结合使用很麻烦 使用这种方法,您仍然拥有通过NHibernate映射和填充的private lines字段;但是,对集合的公共访问是通过迭代器执行的。您不能使用此lines属性添加到基础列表或从中删除 例如:
public IEnumerable<OrderLine> Lines {
get {
foreach (OrderLine aline in lines) {
yield return aline;
}
}
}
公共IEnumerable行{
得到{
foreach(订单行中的aline){
收益率;
}
}
}
我是这样做的:
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 )
{
...
}
}
公共类秩序
{
私有ISet_orderLines=new HashedSet();
公共只读集合医嘱行
{
获取{返回新列表(_orderLines).AsReadOnly();}
}
公共无效添加医嘱行(医嘱行ol)
{
...
}
}
当然,在映射中,NHibernate被告知使用_orderLines字段:
<set name="OrderLine" access="field.camelcase-underscore" ... >
...
</set>
...
我花了几天时间在NHibernate中寻找只读列表的最佳方法。
这次讨论帮助我形成了一个适合我们项目的方案
我开始使用一种方法:
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; }
}
公共类秩序
{
私有只读IList行=新列表();
公共虚拟可数线
{
得到
{
返回新的只读集合(行);
}
}
公共无效添加行(订单行)
{
如果(!line.Contains(line))
{
this.lines.Add(行);
line.Order=this;
}
}
公共无效删除行(订单行)
{
if(行.包含(行))
{
此。行。删除(行);
line.Order=null;
}
}
}
公共类命令行
{
公共秩序{get;set;}
}
为什么不只“返回行”?您是在保护不被强制转换?解决方案的收益率意味着Count()将需要foreach并将加载所有备份的ites(在延迟加载的情况下).IEnumerable与yield相结合,允许您在不添加/删除项的情况下遍历集合。好的,IEnumerable本身也会阻止您添加/删除项-因此,public IEnumerable行{get{return Lines;}
应该足够了。使用您的代码,以下代码将失败:order.OrderLines!=order.OrderLines;我不确定这是否是错误的…无论如何,谢谢。这并不重要,因为您不应该这样比较:)很好的解决方案。这对我帮助很大。谢谢!您为什么选择返回新的而不是缓存ReadOnlyCollectionn在一个懒惰的私有字段中?如果您要返回new,我认为最好按照其他人的建议执行返回新的ReadOnlyCollection(\u orderLines)
。这是因为.AsReadOnly()
返回一个仍然有添加()
(调用时只是抛出异常),而ReadOnlyCollection
(来自System.Collections.ObjectModel)没有,因此确保没有人考虑错误地使用只读集合。关于“Order.Lines[0]=new OrderLine();”它不能。每次访问这些行时,都会发布新的数组副本(但我不喜欢这样…).IEnumerable缺少列表功能,我的意思是计数,按索引访问。当然,LINQ也包括了这一点。谢谢!在这里,您仍然可以将Lines属性强制转换为列表并以这种方式修改集合…是的,但您必须执行强制转换。这不是关于保护,而是关于显示允许对集合执行的操作。Y您可以返回此.lines.AsReadonly()如果你想获得额外的安全性。我同意gcores的观点,关键是要通过公共界面大声传达你要做的事情。如果你想通过施放进行黑客攻击,你可以这样做,但即使你复制它,也有人可以使用反射来获取底层列表。@Rezler是的,你必须这样做。是的,似乎是IEnumerable beats ReadOnly Collection…ReadOnlyCollection使API变得混乱。它仍然有Add方法,在运行时会引发异常…Mike--我认为您在这方面搞错了。返回列表。AsReadOnly()确实公开了Add方法,但ReadOnlyCollection没有。ReadOnlyCollection位于System.Collections.ObjectModel中,因此它经常被忽略。很有趣,是的,这是真的。我忽略了它。非常感谢。
<set name="OrderLine" access="field.camelcase-underscore" ... >
...
</set>
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; }
}