2009-06-03 20 views
11

因此,在一个典型的模型中,如果父母可以有多个孩子并且孩子只能有一个父母,那么您如何管理孩子的添加。我一直在使用这种方法;处理NHibernate父子集合的最佳实践

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

有没有关于此方面的最佳实践的指导,你做了什么?

回答

2

我那样做,只是我不为私人列表使用属性

private IList<Child> _children 
public IEnumerable<Child> Children 
{ 
    get 
    { 
     return children; 
    } 
} 
10

这不是一个NHibernate的问题。

您应该实施AddChild方法。这些类对它们的一致性负责,所以它们不应该公开任何不可用的东西。例如,(可变)儿童列表应该隐藏。公开IEnumerable是个好主意。

你的第二个代码是一个很好的起点。您可能需要一些更多的方法,如RemoveChild或CoundChildren。

+0

说到第二个例子,我唯一担心的是如何使用Linq到NHibernate。由于实际映射的属性现在是私人的,我会假设它不会被视为可见的。有什么想法吗? – Gareth 2009-06-03 11:33:42

+0

您可以在您的映射中指定NHibernte在设置值时应该使用字段而不是属性。 (例如看一下访问属性)。 – 2009-06-03 12:07:13

+0

是的,我得到的是当Linq到NHibernate完成时,如果该字段是私有的,并且公共访问只返回对原始集合的引用,那么如何使用它。例如。 (x => x.Children.Name.Equals(“Jonnie”)) – Gareth 2009-06-03 12:54:33

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

所以,其实,这是一个有点什么斯特凡说为好。我只是公开一个只读的Children列表副本,以便您可以轻松遍历父代的子代,并获取父代所拥有的子代数。 向父项添加和删除子项必须使用AddChild & RemoveChild成员方法完成。

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

我使用的是公共IEnumerable的有添加|删除方法的方法。

但是我不喜欢它,因为它不直观,并且会影响类的定义。

我想知道为什么人们不使用CustomCollection他们重写添加,删除,替换功能? (就像MS代码中无处不在)?

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属性上还有其他选项,允许使用各种命名配置。

0

如果您的数据库中有一个外键,并且您使用标识(SQL Server)生成主键,则您将要从子项到父项的反向链接需要需要。否则,该插入会对孩子抱怨,因为nhibernate需要为父ID进行一些来回处理,但它尚未完成。

我们最终做了什么来摆脱反向链接:使用NHibernate HiLo生成器。 这样,NHibernate始终拥有它需要插入父/子关系的ID。

< 3!