📄 persistent-classes.html
字号:
<tt class="literal">equals()</tt> 和 <tt class="literal">hashCode()</tt>方法: </p><div class="itemizedlist"><ul type="disc" compact><li><p> 想把持久类的实例放入<tt class="literal">Set</tt>中(当表示多值关联时,推荐这么做) </p></li><li><p> 想重用脱管实例 </p></li></ul></div><p> Hibernate保证,持久化标识(数据库的行)和仅在特定会话范围内的Java标识是等值的。因此,一旦 我们混合了从不同会话中获取的实例,如果我们希望<tt class="literal">Set</tt>有明确的语义,我们必 须实现<tt class="literal">equals()</tt> 和<tt class="literal">hashCode()</tt>。 </p><p> 实现<tt class="literal">equals()</tt>/<tt class="literal">hashCode()</tt>最显而易见的方法是比较两个对象 标识符的值。如果值相同,则两个对象对应于数据库的同一行,因此它们是相等的(如果都被添加到 <tt class="literal">Set</tt>,则在<tt class="literal">Set</tt>中只有一个元素)。不幸的是,对生成的标识不能 使用这种方法。Hibernate仅对那些持久化对象赋标识值,一个新创建的实例将不会有任何标识值。此外, 如果一个实例没有被保存(unsaved),并且在一个<tt class="literal">Set</tt>中,保存它将会给这个对象 赋一个标识值。如果<tt class="literal">equals()</tt> 和 <tt class="literal">hashCode()</tt>是基于标识值 实现的,则其哈希码将会改变,违反<tt class="literal">Set</tt>的契约。建议去Hibernate的站点看关于这个 问题的全部讨论。注意,这不是一个Hibernate问题,而是一般的Java对象标识和相等的语义问题。 </p><p> 我们建议使用<span class="emphasis"><em>业务键值相等(Business key equality)</em></span>来实现<tt class="literal">equals()</tt> 和 <tt class="literal">hashCode()</tt>。业务键值相等的意思是,<tt class="literal">equals()</tt>方法 仅仅比较来自业务键的属性,一个业务键将标识在真实世界里(一个<span class="emphasis"><em>天生的</em></span>候选键) 的实例。 </p><pre class="programlisting">public class Cat { ... public boolean equals(Object other) { if (this == other) return true; if ( !(other instanceof Cat) ) return false; final Cat cat = (Cat) other; if ( !cat.getLitterId().equals( getLitterId() ) ) return false; if ( !cat.getMother().equals( getMother() ) ) return false; return true; } public int hashCode() { int result; result = getMother().hashCode(); result = 29 * result + getLitterId(); return result; }}</pre><p> 注意,业务键不必是象数据库的主键那样是固定不变的(参见<a href="transactions.html#transactions-basics-identity" title="12.1.3. 关注对象标识(Considering object identity)">第 12.1.3 节 “关注对象标识(Considering object identity)”</a>)。 对业务键而言,不可变或唯一的属性是好的候选。 </p></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="persistent-classes-dynamicmodels"></a>5.4. 动态模型(Dynamic models)</h2></div></div><div></div></div><p> <span class="emphasis"><em>注意,以下特性在当前是基于实验考虑的,可能会在将来改变。</em></span> </p><p> 运行期的持久化实体没有必要象POJO类或JavaBean对象一样表示。Hibernate也支持动态模型 (在运行期使用<tt class="literal">Map</tt>的<tt class="literal">Map</tt>)和象DOM4J的树模型那 样的实体表示。使用这种方法,你不用写持久化类,只写映射文件就行了。 </p><p> Hibernate默认工作在普通POJO模式。你可以使用配置选项<tt class="literal">default_entity_mode</tt>, 对特定的<tt class="literal">SessionFactory</tt>,设置一个默认的实体表示模式。 (参见<a href="session-configuration.html#configuration-optional-properties" title="表 4.3. 
 Hibernate配置属性
 ">表 4.3 “ Hibernate配置属性 ”</a>。) </p><p> 下面是用<tt class="literal">Map</tt>来表示的例子。首先,在映射文件中,要声明 <tt class="literal">entity-name</tt>来代替(或外加)一个类名。 </p><pre class="programlisting"><hibernate-mapping> <class entity-name="Customer"> <id name="id" type="long" column="ID"> <generator class="sequence"/> </id> <property name="name" column="NAME" type="string"/> <property name="address" column="ADDRESS" type="string"/> <many-to-one name="organization" column="ORGANIZATION_ID" class="Organization"/> <bag name="orders" inverse="true" lazy="false" cascade="all"> <key column="CUSTOMER_ID"/> <one-to-many class="Order"/> </bag> </class> </hibernate-mapping></pre><p> 注意,虽然是用目标类名来声明关联的,但是关联的目标类型除了是POJO之外,也可以 是一个动态的实体。 </p><p> 在使用<tt class="literal">dynamic-map</tt>为<tt class="literal">SessionFactory</tt> 设置了默认的实体模式之后,可以在运行期使用<tt class="literal">Map</tt>的 <tt class="literal">Map</tt>。 </p><pre class="programlisting">Session s = openSession();Transaction tx = s.beginTransaction();Session s = openSession();// Create a customerMap david = new HashMap();david.put("name", "David");// Create an organizationMap foobar = new HashMap();foobar.put("name", "Foobar Inc.");// Link bothdavid.put("organization", foobar);// Save boths.save("Customer", david);s.save("Organization", foobar);tx.commit();s.close();</pre><p> 动态映射的好处是,使原型在不需要实体类实现的情况下,快速转变时间。然而,你无法进行 编译期的类型检查,并可能由此会处理很多的运行期异常。幸亏有了Hibernate映射,它使得数 据库的schema能容易的规格化和合理化,并允许稍后添加正确的领域模型的最新实现。 </p><p> 实体表示模式也能在每个<tt class="literal">Session</tt>的基础上设置: </p><pre class="programlisting">Session dynamicSession = pojoSession.getSession(EntityMode.MAP);// Create a customerMap david = new HashMap();david.put("name", "David");dynamicSession.save("Customer", david);...dynamicSession.flush();dynamicSession.close()...// Continue on pojoSession</pre><p> 请注意,用<tt class="literal">EntityMode</tt>调用<tt class="literal">getSession()</tt>是在 <tt class="literal">Session</tt>的API中,而不是<tt class="literal">SessionFactory</tt>。 这样,新的<tt class="literal">Session</tt>共享底层的JDBC连接,事务,和其他的上下文信 息。这意味着,你不需要在第二个<tt class="literal">Session</tt>中调用 <tt class="literal">flush()</tt>和<tt class="literal">close()</tt>,同样的,把事务和连接的处理 交给原来的工作单元。 </p><p> 关于XML表示能力的更多信息可以在<a href="xml.html" title="第 19 章 XML映射">第 19 章 <i>XML映射</i></a>中找到。 </p></div><p> TODO:在property和proxy的包里,用户扩展文件框架。 </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="session-configuration.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="mapping.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">第 4 章 配置 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 第 6 章 对象/关系数据库映射基础(Basic O/R Mapping)</td></tr></table></div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -