📄 example-parentchild.html
字号:
<html><head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>第 22 章 示例:父子关系(Parent Child Relationships)</title><link rel="stylesheet" href="../shared/css/html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="HIBERNATE - 符合Java习惯的关系数据库持久化"><link rel="up" href="index.html" title="HIBERNATE - 符合Java习惯的关系数据库持久化"><link rel="previous" href="toolsetguide.html" title="第 21 章 工具箱指南"><link rel="next" href="example-weblog.html" title="第 23 章 示例:Weblog 应用程序"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">第 22 章 示例:父子关系(Parent Child Relationships)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="toolsetguide.html">上一页</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="example-weblog.html">下一页</a></td></tr></table><hr></div><div class="chapter" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title"><a name="example-parentchild"></a>第 22 章 示例:父子关系(Parent Child Relationships)</h2></div></div><div></div></div><p> 刚刚接触Hibernate的人大多是从父子关系(parent / child type relationship)的建模入手的。父子关系的建模有两种方法。由于种种原因,最方便的方法是把<tt class="literal">Parent</tt>和<tt class="literal">Child</tt>都建模成实体类,并创建一个从<tt class="literal">Parent</tt>指向<tt class="literal">Child</tt>的<one-to-many>关联,对新手来说尤其如此。还有一种方法,就是将<tt class="literal">Child</tt>声明为一个<tt class="literal"><composite-element></tt>(组合元素)。 事实上在Hibernate中one to many关联的默认语义远没有composite element贴近parent / child关系的通常语义。下面我们会阐述如何使用<span class="emphasis"><em>带有级联的双向一对多关联(bidirectional one to many association with cascades)</em></span>去建立有效、优美的parent / child关系。这一点也不难! </p><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="example-parentchild-collections"></a>22.1. 关于collections需要注意的一点</h2></div></div><div></div></div><p> Hibernate collections被当作其所属实体而不是其包含实体的一个逻辑部分。这非常重要!它主要体现为以下几点: </p><div class="itemizedlist"><ul type="disc"><li><p> 当删除或增加collection中对象的时候,collection所属者的版本值会递增。 </p></li><li><p> 如果一个从collection中移除的对象是一个值类型(value type)的实例,比如composite element,那么这个对象的持久化状态将会终止,其在数据库中对应的记录会被删除。同样的,向collection增加一个value type的实例将会使之立即被持久化。 </p></li><li><p> 另一方面,如果从一对多或多对多关联的collection中移除一个实体,在缺省情况下这个对象并不会被删除。这个行为是完全合乎逻辑的--改变一个实体的内部状态不应该使与它关联的实体消失掉!同样的,向collection增加一个实体不会使之被持久化。 </p></li></ul></div><p> 实际上,向Collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已,同样移除的时候也只是删除连接。这种处理对于所有的情况都是合适的。对于父子关系则是完全不适合的,在这种关系下,子对象的生存绑定于父对象的生存周期。 </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="example-parentchild-bidir"></a>22.2. 双向的一对多关系(Bidirectional one-to-many)</h2></div></div><div></div></div><p> 假设我们要实现一个简单的从Parent到Child的<one-to-many>关联。 </p><pre class="programlisting"><set name="children"> <key column="parent_id"/> <one-to-many class="Child"/></set></pre><p> 如果我们运行下面的代码 </p><pre class="programlisting">Parent p = .....;Child c = new Child();p.getChildren().add(c);session.save(c);session.flush();</pre><p> Hibernate会产生两条SQL语句: </p><div class="itemizedlist"><ul type="disc"><li><p>一条<tt class="literal">INSERT</tt>语句,为<tt class="literal">c</tt>创建一条记录</p></li><li><p> 一条<tt class="literal">UPDATE</tt>语句,创建从<tt class="literal">p</tt>到<tt class="literal">c</tt>的连接 </p></li></ul></div><p> 这样做不仅效率低,而且违反了列<tt class="literal">parent_id</tt>非空的限制。我们可以通过在集合类映射上指定<tt class="literal">not-null="true"</tt>来解决违反非空约束的问题: </p><pre class="programlisting"><set name="children"> <key column="parent_id" not-null="true"/> <one-to-many class="Child"/></set></pre><p> 然而,这并非是推荐的解决方法。 </p><p> 这种现象的根本原因是从<tt class="literal">p</tt>到<tt class="literal">c</tt>的连接(外键parent_id)没有被当作<tt class="literal">Child</tt>对象状态的一部分,因而没有在INSERT语句中被创建。因此解决的办法就是把这个连接添加到Child的映射中。 </p><pre class="programlisting"><many-to-one name="parent" column="parent_id" not-null="true"/></pre><p> (我们还需要为类<tt class="literal">Child</tt>添加<tt class="literal">parent</tt>属性) </p><p> 现在实体<tt class="literal">Child</tt>在管理连接的状态,为了使collection不更新连接,我们使用<tt class="literal">inverse</tt>属性。 </p><pre class="programlisting"><set name="children" inverse="true"> <key column="parent_id"/> <one-to-many class="Child"/></set></pre><p> 下面的代码是用来添加一个新的<tt class="literal">Child</tt> </p><pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);Child c = new Child();c.setParent(p);p.getChildren().add(c);session.save(c);session.flush();</pre><p> 现在,只会有一条<tt class="literal">INSERT</tt>语句被执行! </p><p> 为了让事情变得井井有条,可以为<tt class="literal">Parent</tt>加一个<tt class="literal">addChild()</tt>方法。 </p><pre class="programlisting">public void addChild(Child c) { c.setParent(this); children.add(c);}</pre><p> 现在,添加<tt class="literal">Child</tt>的代码就是这样
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -