NHibernate映射子集合和嵌入式子实例

时间:2010-08-20 12:37:24

标签: nhibernate nhibernate-mapping

我正在试图找出映射以下父子关系的正确方法。我有一个包含子对象的父类。但是,父级还有一个指向其中一个子级(PrimaryChild)

的实例的指针
Class Parent

  Public Property Id As Integer?

  Public Property PrimaryChild As Child

  Public Property Children As IList(Of Child)

End Class

Public Class Child

    Public Property Id As Integer?

    Public MyParent As Parent

End Class

用法类似于

Dim ch As New Child
Dim par as New Parent

ch.MyParent = par
par.Children.Add(ch)

par.PrimaryChild = ch

Session.SaveOrUpdate(par)

但是,当我这样做时,PrimaryChild显示为null或transient值。我在Children系列上设置了cascade =“all”。

任何想法我做错了什么?

更新1

添加了映射

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Parent" table="Parents">
    <id name="Id" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="ID" />
    </id>

    <set access="nosetter.camelcase-underscore" cascade="all-delete-orphan" inverse="true" name="Children" mutable="true">
      <key>
        <column name="ParentID" />
      </key>
      <one-to-many class="Child" />
    </set>
    <many-to-one cascade="save-update" class="Child" name="PrimaryChild">
      <column name="PrimaryChildID" not-null="true" />
    </many-to-one>
    <many-to-one cascade="save-update" class="Child" name="SecondaryChild">
      <column name="SecondaryChildID" not-null="true" />
    </many-to-one>
  </class>
</hibernate-mapping>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="Child" table="Child">
    <id name="Id" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="ID" />
    </id>
    <many-to-one class="Parent" name="Parent">
      <column name="ParentID" not-null="true" />
    </many-to-one>
  </class>
</hibernate-mapping>

4 个答案:

答案 0 :(得分:1)

你的桌子看起来像这样:

Table Parent
(
  ...
  PrimaryChild_FK NOT NULL
)

Table Child
(
  ...
  Paren_FK NOT NULL
)

您能告诉我数据的插入顺序吗?您既不能插入Parent也不能插入Child,因为两者都需要另一个来设置外键。 (NHibernate插入其中一个并将FK设置为​​null,以便稍后更新。但数据库会抱怨。)

从集合中删除非空约束。如果只删除其中一个,NHibernate不够智能,无法找到有效的插入顺序。 (AFAIK,映射文件中的非空约束实际上仅用于从中创建数据库模式。)

正如mathieu已经提到的那样,将set设置为inverse并对child-parent和parent-children关系使用相同的外键。

答案 1 :(得分:0)

到目前为止,你有什么样的映射?

PrimaryChild是一对一的,Children是一对多的,但您可以通过多种方式管理这种关系。你的外国钥匙在哪里?

如果你把FK放在Child上,那么你想要同时设置inverse=true的一对一和一对多映射。

顺便说一下,这个:

ch.MyParent = par
par.Children.Add(ch)

是一个大规模的OO封装失败。 Parent不应该公开IList,因为其他对象可以操纵它。 parent类应该控制自身的所有操作。使它成为IEnumerable并使用AddChild方法完成上述两行。

答案 2 :(得分:0)

我使用像NHibernate LINQ库这样的工具执行了这项任务。

public class Parent {
  public Parent() {
    Children = new List<Child>();
  }
  public virtual IList<Child> Children { get; set; }
  public virtual Child PrimaryChild {
      get {
        return Children.FirstOrDefault(x => x.IsPrimary);
    }
  }
}

如果您已经加载了孩子,那么PrimaryChild是一个内存中的操作。如果您首先请求PrimaryChild,那么这将是它自己的数据库提取操作。很好地工作,IMO。

你应该看看安德鲁·布洛克的回应。公开IList打开了通往糟糕域设计的大门。您应该只公开枚举。

答案 3 :(得分:0)

如果您的关系是双向的(IE父级引用子级,子级引用父级),并且外键位于Child上,则需要设置属性

inverse="true"

在集合的声明中。否则级联将无法正常工作:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Parent">
    <id name="Id" />

    <bag name="Children" cascade="all" inverse="true">
      <key column="ID_PARENT" />
      <one-to-many class="Child"/>
    </bag>
  </class>

  <class name="Children">
    <id name="Id" />

    <many-to-one name="Parent" column="ID_PARENT" class="Parent" not-null="true" />
  </class>
</hibernate-mapping>
相关问题