📄 example-parentchild.html
字号:
</p><pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);Child c = new Child();p.addChild(c);session.save(c);session.flush();</pre></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="example-parentchild-cascades"></a>22.3. 级联生命周期(Cascading lifecycle)</h2></div></div><div></div></div><p> 需要显式调用<tt class="literal">save()</tt>仍然很麻烦,我们可以用级联来解决这个问题。 </p><pre class="programlisting"><set name="children" inverse="true" cascade="all"> <key column="parent_id"/> <one-to-many class="Child"/></set></pre><p> 这样上面的代码可以简化为: </p><pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);Child c = new Child();p.addChild(c);session.flush();</pre><p> 同样的,保存或删除<tt class="literal">Parent</tt>对象的时候并不需要遍历其子对象。 下面的代码会删除对象<tt class="literal">p</tt>及其所有子对象对应的数据库记录。 </p><pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);session.delete(p);session.flush();</pre><p> 然而,这段代码 </p><pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);Child c = (Child) p.getChildren().iterator().next();p.getChildren().remove(c);c.setParent(null);session.flush();</pre><p> 不会从数据库删除<tt class="literal">c</tt>;它只会删除与<tt class="literal">p</tt>之间的连接(并且会导致违反<tt class="literal">NOT NULL</tt>约束,在这个例子中)。你需要显式调用<tt class="literal">delete()</tt>来删除<tt class="literal">Child</tt>。 </p><pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);Child c = (Child) p.getChildren().iterator().next();p.getChildren().remove(c);session.delete(c);session.flush();</pre><p> 在我们的例子中,如果没有父对象,子对象就不应该存在,如果将子对象从collection中移除,实际上我们是想删除它。要实现这种要求,就必须使用<tt class="literal">cascade="all-delete-orphan"</tt>。 </p><pre class="programlisting"><set name="children" inverse="true" cascade="all-delete-orphan"> <key column="parent_id"/> <one-to-many class="Child"/></set></pre><p> 注意:即使在collection一方的映射中指定<tt class="literal">inverse="true"</tt>,级联仍然是通过遍历collection中的元素来处理的。如果你想要通过级联进行子对象的插入、删除、更新操作,就必须把它加到collection中,只调用<tt class="literal">setParent()</tt>是不够的。 </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="example-parentchild-update"></a>22.4. 级联与<tt class="literal">未保存值</tt>(Cascades and <tt class="literal">unsaved-value</tt>)</h2></div></div><div></div></div><p> 假设我们从<tt class="literal">Session</tt>中装入了一个<tt class="literal">Parent</tt>对象,用户界面对其进行了修改,然后希望在一个新的Session里面调用<tt class="literal">update()</tt>来保存这些修改。对象<tt class="literal">Parent</tt>包含了子对象的集合,由于打开了级联更新,Hibernate需要知道哪些Child对象是新实例化的,哪些代表数据库中已经存在的记录。我们假设<tt class="literal">Parent</tt>和<tt class="literal">Child</tt>对象的标识属性都是自动生成的,类型为<tt class="literal">java.lang.Long</tt>。Hibernate会使用标识属性的值,和version 或 timestamp 属性,来判断哪些子对象是新的。(参见<a href="objectstate.html#objectstate-saveorupdate" title="11.7. 自动状态检测">第 11.7 节 “自动状态检测”</a>.) <span class="emphasis"><em>在 Hibernate3 中,显式指定<tt class="literal">unsaved-value</tt>不再是必须的了。</em></span> </p><p> 下面的代码会更新<tt class="literal">parent</tt>和<tt class="literal">child</tt>对象,并且插入<tt class="literal">newChild</tt>对象。 </p><pre class="programlisting">//parent and child were both loaded in a previous sessionparent.addChild(child);Child newChild = new Child();parent.addChild(newChild);session.update(parent);session.flush();</pre><p> Well, that's all very well for the case of a generated identifier, but what about assigned identifiers and composite identifiers? This is more difficult, since Hibernate can't use the identifier property to distinguish between a newly instantiated object (with an identifier assigned by the user) and an object loaded in a previous session. In this case, Hibernate will either use the timestamp or version property, or will actually query the second-level cache or, worst case, the database, to see if the row exists. </p><p> 这对于自动生成标识的情况是非常好的,但是自分配的标识和复合标识怎么办呢?这是有点麻烦,因为Hibernate没有办法区分新实例化的对象(标识被用户指定了)和前一个Session装入的对象。在这种情况下,Hibernate会使用timestamp或version属性,或者查询第二级缓存,或者最坏的情况,查询数据库,来确认是否此行存在。</p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="example-parentchild-conclusion"></a>22.5. 结论</h2></div></div><div></div></div><p> 这里有不少东西需要融会贯通,可能会让新手感到迷惑。但是在实践中它们都工作地非常好。大部分Hibernate应用程序都会经常用到父子对象模式。 </p><p> 在第一段中我们曾经提到另一个方案。上面的这些问题都不会出现在<tt class="literal"><composite-element></tt>映射中,它准确地表达了父子关系的语义。很不幸复合元素还有两个重大限制:复合元素不能拥有collections,并且,除了用于惟一的父对象外,它们不能再作为其它任何实体的子对象。 </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="toolsetguide.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="example-weblog.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">第 21 章 工具箱指南 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 第 23 章 示例:Weblog 应用程序</td></tr></table></div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -