因此,在一个典型的模型中,您的父母可以拥有许多孩子,而且孩子只能拥有一个父母,那么如何管理孩子的添加。我一直在使用这种方法;
public class Parent
{
public Parent()
{
Children = new List<Child>();
}
public IList<Child> Children
{
get;
private set;
}
}
public class Child
{
public Parent Parent
{
get;
set;
}
}
var child = new Child();
var parent = new Parent();
parent.Children.Add(child);
child.Parent = parent;
问题是,无论我想添加一个新的孩子,我都必须记住添加对孩子和父母的引用,这有点痛苦。我可以将AddChild方法添加到父类,并使其负责添加子项 - 现在的问题是有两种方法可以通过Children属性和方法添加子项。那么这是一个更好的解决方案吗?
public class Parent
{
public Parent()
{
children = new List<Child>();
}
private IList<Child> children
{
get;
private set;
}
public IEnumerable<Child> Children
{
get
{
return children;
}
}
public void AddChild(Child child)
{
children.Add(child);
child.Parent = this;
}
}
对此有最佳实践的指导吗,你做了什么?
答案 0 :(得分:10)
这根本不是NHibernate的问题。
您应该实现AddChild方法。这些类对它们的一致性负责,所以它们不应该暴露任何不可用的东西。例如,应隐藏(可变)子列表。公开IEnumerable是个好主意。
你的第二个代码是一个很好的起点。您可能需要更多方法,例如RemoveChild或CoundChildren。
答案 1 :(得分:5)
我这样做:
public class Parent
{
private ISet<Child> _children = new HashedSet<Child>();
public ReadOnlyCollection<Child> Children
{
get{ return new List(_children).AsReadOnly(); }
}
public void AddChild( Child c )
{
if( c != null && !_children.Contains (d) )
{
c.Parent = this;
_children.Add (c);
}
}
}
所以,事实上,这也是Stefan所说的。我只是暴露了Children列表的只读副本,这样您就可以轻松地遍历父项的子项,并获得父项的子项数。 添加和删除父项的子项必须使用AddChild&amp; amp; RemoveChild成员方法。
答案 2 :(得分:2)
我是这样做的,除了我不使用私有列表属性
private IList<Child> _children
public IEnumerable<Child> Children
{
get
{
return children;
}
}
答案 3 :(得分:1)
我正在使用公共IEnumerable和Add | Remove methods方法。
但是我不喜欢它,因为它不直观,并且对类定义进行了调查。
我想知道为什么人们不使用CustomCollection来覆盖Add,Remove,Replace函数? (就像在MS代码中到处都做的那样)????
答案 4 :(得分:0)
我支持此问题的已接受解决方案,但是所提供的解决方案并不完整,因为使用私有字段需要在映射器中进行一些额外配置。为了其他人的利益,以下是完整的解决方案:
public partial class Test
{
private readonly IList<Child> children = new List<Child>();
public virtual IEnumerable<Child> Children
{
get
{
return children;
}
}
}
请注意,公开公开的集合必须是虚拟的,以便NHibernate使用它。我还想使它成为一个只读字段,在创建类时初始化该字段以确保它存在于所有场景中。这是关联的映射器:
public class TestMap : ClassMap<Test>
{
...
HasMany(s => s.Children).Access.CamelCaseField();
}
Access属性告诉NHibernate在将值映射到模型时使用私有字段。 Access属性上还有其他选项,允许使用各种命名配置。
答案 5 :(得分:0)
如果您的数据库中有外键,并且您正在使用Identity(SQL Server)生成主键,那么您将 NEED 从子项到父项的反向链接。否则,插入内容会对孩子抱怨,因为nhibernate需要为父ID来回做一些,但它还没有完成。
我们最终做了什么来摆脱反向链接:使用NHibernate HiLo生成器。 这样,NHibernate总是具有插入父/子关系所需的ID。
&lt; 3!
答案 6 :(得分:-1)
我不喜欢所有额外的AddXXX()
和RemoveXXX()
方法混乱我的实体接口。相反,我有一个自定义列表,可以在调用Add()
和Remove()
方法时引发事件。
然后在事件处理程序中发生链接:
public class Course()
{
public Course()
{
this.Topics = new EntityList<Topic>();
this.Topics.AddItem += new AddItemEventHandler<Topic>(Topic_AddItem);
this.Topics.RemoveItem += new RemoveItemEventHandler<Topic>(Topic_RemoveItem);
}
public EntityList<Topic> Topics { get; private set; }
private void Topic_AddItem(Topic item, object args)
{
// Replace with your linking code:
EntityLinker.Link(this).With(item, args);
}
private void Topic_RemoveItem(Topic item, object args)
{
// Replace with your unlinking code:
EntityLinker.Unlink(this).From(item, args);
}
}