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

发布于 2024-09-14 21:12:21 字数 2534 浏览 3 评论 0原文

我试图找出映射以下父子关系的正确方法。我有一个包含子对象的父类。但是,父级还有一个指向子级之一的实例(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 显示为空值或瞬态值。我已经在 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>

I'm trying to figure what's the correct way to map the following parent child relationship. I have a parent class which contains child objects. However, the parent also has a pointer to an instance of one of the children (the 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

Usage is something like

Dim ch As New Child
Dim par as New Parent

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

par.PrimaryChild = ch

Session.SaveOrUpdate(par)

However, when I do this, the PrimaryChild is shown as being a null or transient value. I have set cascade="all" on the Children collection.

Any ideas what I'm doing wrong?

Update 1

Added Mappings

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

メ斷腸人バ 2024-09-21 21:12:21

您的表如下所示:

Table Parent
(
  ...
  PrimaryChild_FK NOT NULL
)

Table Child
(
  ...
  Paren_FK NOT NULL
)

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

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

正如 mathieu 已经提到的,使集合反转并为子父关系和父子关系使用相同的外键。

Your tables are looking like this:

Table Parent
(
  ...
  PrimaryChild_FK NOT NULL
)

Table Child
(
  ...
  Paren_FK NOT NULL
)

Can you tell me in which order the data should be inserted? You can neither insert Parent nor Child, since both need the other to set the foreign key. (NHibernate inserts one of them and set the FK to null, to update it later. But the database complains.)

Remove the not null constraint from the set. NHibernate is not smart enough to find a working insert order if you just remove one of them. (AFAIK, not null constraints in the mapping files are actually only used to create the database schema from).

And as already mentioned by mathieu, make the set inverse and use the same foreign key for the child-parent and the parent-children relations.

计㈡愣 2024-09-21 21:12:21

我已经使用 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,那么这将是它自己的数据库获取操作。效果很好,国际海事组织。

你应该看看安德鲁·布洛克的回应。公开 IList 会导致糟糕的域设计。您应该只公开枚举。

I've performed this task with tools like the NHibernate LINQ library.

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

If you've already loaded the children, then PrimaryChild is an in-memory operation. If you request PrimaryChild first, then this will be it own database fetch operation. Works nicely, IMO.

And you should look at Andrew Bullock's response. Exposing an IList opens the door to bad domain design. You should only expose the enumeration.

被你宠の有点坏 2024-09-21 21:12:21

到目前为止,您有哪些映射?

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

如果您将 FK 放在 Child 上,那么您需要一对一和一对多映射,并在两者上设置 inverse=true

顺便说一句,这

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

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

What mappings do you have so far?

PrimaryChild is a one-to-one, Children is a one-to-many but you could manage the relationship in many different ways. Where are your Foreign Keys?

if you put the FK on the Child, then you want both one-to-one and one-to-many mappings with inverse=true set on both.

As an aside, this:

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

is a massive OO encapsulation fail. Parent shouldn't expose an IList, as other objects can manipulate it. The parent class should control all manipulations of itself. Make it an IEnumerable and use an AddChild method that does the above two lines.

请别遗忘我 2024-09-21 21:12:21

如果您的关系是双向的(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>

If your relation is bidirectional (IE parent references children, and child references parent), and if the foreign key is on Child, you need to set the attribute

inverse="true"

in the declaration of the collection. Otherwise cascade won't work nicely :

<?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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文