处理NHibernate父子集合的最佳实践

处理NHibernate父子集合的最佳实践,nhibernate,domain-driven-design,Nhibernate,Domain Driven Design,因此,在一个典型的模型中,如果父对象可以有多个子对象,而子对象只能有一个父对象,那么如何管理子对象的添加。我一直在使用这种方法 public class Parent { public Parent() { Children = new List<Child>(); } public IList<Child> Children { get; private set; } }

因此,在一个典型的模型中,如果父对象可以有多个子对象,而子对象只能有一个父对象,那么如何管理子对象的添加。我一直在使用这种方法

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;
公共类父类
{
公共家长()
{
Children=新列表();
}
公营儿童
{
得到;
私人设置;
}
}
公营儿童
{
公共家长
{
得到;
设置
}
}
var child=new child();
var 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;
    }
}
公共类父类
{
公共家长()
{
children=新列表();
}
私人儿童
{
得到;
私人设置;
}
可数儿童的公共教育
{
得到
{
返回儿童;
}
}
公共无效添加子对象(子对象)
{
添加(child);
child.Parent=this;
}
}

关于这方面的最佳实践有什么指南吗?你是怎么做的?

这根本不是NHibernate的问题

您应该实现AddChild方法。这些类负责它们的一致性,因此它们不应该公开任何不可用的内容。例如,(可变)子列表应该隐藏。公开IEnumerable是个好主意

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

我是这样做的:

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);
       }
    }
}
公共类父类
{
私有ISet_children=new HashedSet();
公共只读集合子项
{
获取{返回新列表(_children).AsReadOnly();}
}
公共无效添加子项(子项c)
{
如果(c!=null&&!\u children.Contains(d))
{
c、 父=此;
_添加(c);
}
}
}
所以,事实上,斯特凡也是这么说的。我只公开子列表的只读副本,这样您就可以轻松地迭代父级的子级,并获得父级的子级数。
必须使用AddChild和RemoveChild成员方法向父级添加和删除子级。

我不喜欢所有额外的
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);
   }   
}
公共课()
{
公共课程()
{
this.Topics=newentitylist();
this.Topics.AddItem+=新的AddItemEventHandler(Topic\u AddItem);
this.Topics.removietem+=新的removietemeventhandler(Topic\u removietem);
}
公共实体列表主题{get;private set;}
私有无效主题\附加项(主题项、对象参数)
{
//替换为您的链接代码:
EntityLinker.Link(this).With(item,args);
}   
私有无效主题\u removietem(主题项、对象参数)
{
//替换为您的取消链接代码:
EntityLinker.Unlink(this).From(项,参数);
}   
}

我就是这样做的,只是我不将属性用于私有列表

private IList<Child> _children
public IEnumerable<Child> Children
{
    get
    {
        return children;
    }
}
private IList\u子级
可数儿童的公共教育
{
得到
{
返回儿童;
}
}

我正在使用public IEnumerable和Add | Remove方法

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


我想知道为什么人们不用CustomCollection覆盖添加、删除和替换功能??(就像MS代码中的所有地方一样)?

我支持此问题的公认解决方案,但所提供的解决方案并不完整,因为使用私有字段需要在映射程序中进行一些额外配置。为了其他人的利益,以下是完整的解决方案:

public partial class Test
{
    private readonly IList<Child> children = new List<Child>();
    public virtual IEnumerable<Child> Children
    {
        get
        {
            return children;
        }
    }
}
公共部分类测试
{
private readonly IList children=new List();
公共虚拟可数子对象
{
得到
{
返回儿童;
}
}
}
请注意,公开的集合必须是虚拟的,NHibernate才能使用它。我还喜欢将其设置为只读字段,在创建类时对其进行初始化,以确保它在所有场景中都存在。以下是关联的映射器:

public class TestMap : ClassMap<Test>
{
    ...
    HasMany(s => s.Children).Access.CamelCaseField();
}
公共类TestMap:ClassMap
{
...
HasMany(s=>s.Children);
}

Access属性告诉NHibernate在将值映射到模型时使用私有字段。Access属性上还有其他选项,允许使用各种命名配置。

如果数据库中有外键,并且使用Identity(SQL Server)生成主键,则需要从子项到父项的反向链接。否则,insert将在child上发出抱怨,因为nhibernate需要对父ID来回执行一些操作,但它还没有完成

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


谈到第二个例子,我唯一关心的是如何与Linq to NHibernate合作。由于实际映射的属性现在是私有的,我假设它不可见。有什么想法吗?您可以在映射中指定NHibernte在设置值时应该使用字段而不是属性。(以访问属性为例)是的,我得到的是当Linq到N的时候