NHibernate 映射子集合和子集合的嵌入实例
我试图找出映射以下父子关系的正确方法。我有一个包含子对象的父类。但是,父级还有一个指向子级之一的实例(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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您的表如下所示:
您能告诉我数据应按什么顺序插入吗?您既不能插入 Parent 也不能插入 Child,因为两者都需要对方来设置外键。 (NHibernate 插入其中之一并将 FK 设置为 null,以便稍后更新。但数据库会抱怨。)
从集合中删除 not null 约束。如果您只是删除其中一个插入顺序,NHibernate 不够智能,无法找到有效的插入顺序。 (据我所知,映射文件中的非空约束实际上仅用于创建数据库模式)。
正如 mathieu 已经提到的,使集合反转并为子父关系和父子关系使用相同的外键。
Your tables are looking like this:
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.
我已经使用 NHibernate LINQ 库等工具执行了此任务。
如果您已经加载了子级,则 PrimaryChild 是内存中操作。如果您首先请求 PrimaryChild,那么这将是它自己的数据库获取操作。效果很好,国际海事组织。
你应该看看安德鲁·布洛克的回应。公开 IList 会导致糟糕的域设计。您应该只公开枚举。
I've performed this task with tools like the NHibernate LINQ library.
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.
到目前为止,您有哪些映射?
PrimaryChild
是一对一,Children
是一对多,但您可以通过多种不同的方式管理关系。你的外键在哪里?如果您将 FK 放在 Child 上,那么您需要一对一和一对多映射,并在两者上设置
inverse=true
。顺便说一句,这
是一个巨大的 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:
is a massive OO encapsulation fail.
Parent
shouldn't expose an IList, as other objects can manipulate it. Theparent
class should control all manipulations of itself. Make it an IEnumerable and use anAddChild
method that does the above two lines.如果您的关系是双向的(IE 父级引用子级,子级引用父级),并且外键位于 Child 上,则需要
在集合的声明中设置该属性。否则级联将无法很好地工作:
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
in the declaration of the collection. Otherwise cascade won't work nicely :