📄 collections.html
字号:
一个map,通过字符串的索引来指明日期: </p><pre class="programlisting"><map name="holidays" table="holidays" schema="dbo" order-by="hol_name asc"> <key column="id"/> <index column="hol_name" type="string"/> <element column="hol_date" type="date"/></map></pre><p> 一个组件的列表: </p><pre class="programlisting"><list name="carComponents" table="car_components"> <key column="car_id"/> <index column="posn"/> <composite-element class="com.illflow.CarComponent"> <property name="price" type="float"/> <property name="type" type="com.illflow.ComponentType"/> <property name="serialNumber" column="serial_no" type="string"/> </composite-element></list></pre></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="collections-s1-6"></a>6.4. 一对多关联(One To Many Associations)</h2></div></div><div></div></div><p> <span class="emphasis"><em>一对多关联</em></span><span class="emphasis"><em>直接</em></span>连接两个类对应的表,而没有中间集合表。(这实现了一个<span class="emphasis"><em>一对多</em></span>的关系模型)(译者注:这有别与多对多的关联需要一张中间表)。 这个关系模型失去了一些Java集合的语义: </p><div class="itemizedlist"><ul type="disc" compact><li><p> map,set或list中不能包含null值 </p></li><li><p> 一个被包含的实体的实例只能被包含在一个集合的实例中 </p></li><li><p> 一个被包含的实体的实例只能对应于集合索引的一个值中 </p></li></ul></div><p> 一个从<tt class="literal">Foo</tt>到<tt class="literal">Bar</tt>的关联需要额外的关键字字段,可能还有一个索引字段指向这个被包含的实体类,<tt class="literal">Bar</tt>所对应的表。这些字段在映射时使用前面提到的<tt class="literal"><key></tt>和<tt class="literal"><index></tt>元素。 </p><p> <tt class="literal"><one-to-many></tt>标记指明了一个一对多的关联。 </p><div class="programlistingco"><pre class="programlisting"><one-to-many class="ClassName"/></pre><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><img src="../images/callouts/1.png" alt="1" border="0"></td><td valign="top" align="left"><p> <tt class="literal">class</tt>(必须):被关联类的名称。 </p></td></tr></table></div></div><p> 例子 </p><pre class="programlisting"><set name="bars"> <key column="foo_id"/> <one-to-many class="com.illflow.Bar"/></set></pre><p> 注意:<tt class="literal"><one-to-many></tt>元素不需要定义任何字段。 也不需要指定表名。 </p><p> <span class="emphasis"><em>重要提示</em></span>:如果<tt class="literal">一对多</tt>关联中的<tt class="literal"><key></tt>字段定义成<tt class="literal">NOT NULL</tt>,那么当创建和更新关联关系时Hibernate可能引起约束违例。为了预防这个问题,<span class="emphasis"><em>你必须使用双向关联</em></span>,并且在“多”这一端(Set或者是bag)指明<tt class="literal">inverse="true"</tt>。 </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="collections-s1-7"></a>6.5. 延迟初始化(延迟加载)(Lazy Initialization)</h2></div></div><div></div></div><p> (译者注: 本翻译稿中,对Lazy Initiazation和Eager fetch中的lazy,eager采取意译的方式,分别翻译为延迟初始化和预先抓取。lazt initiazation就是指直到第一次调用时才加载。) </p><p> 集合(不包括数组)是可以延迟初始化的,意思是仅仅当应用程序需要访问时,才载入他们的值。对于使用者来说,初始化是透明的, 因此应用程序通常不需要关心这个(事实上,透明的延迟加载也就是为什么Hibernate需要自己的集合实现的主要原因)。但是, 如何应用程序试图执行以下程序: </p><pre class="programlisting">s = sessions.openSession();User u = (User) s.find("from User u where u.name=?", userName, Hibernate.STRING).get(0);Map permissions = u.getPermissions();s.connection().commit();s.close();Integer accessLevel = (Integer) permissions.get("accounts"); // Error!</pre><p> 这个错误可能令你感到意外。因为在这个<tt class="literal">Session</tt>被提交(commit)之前, permissions没有被初始化,那么这个集合将永远不能载入他的数据了。 解决方法是把读取集合数据的语句提到Session被提交之前。 </p><p> 另外一种选择是不使用延迟初始化集合。既然延迟初始化可能引起上面这样错误,默认是不使用延迟初始化的。但是, 为了效率的原因, 我们希望对绝大多数集合(特别是实体集合)使用延迟初始化。 </p><p> 延迟初始化集合时发生的例外被封装在<tt class="literal">LazyInitializationException</tt>中。 </p><p> 使用可选的 <tt class="literal">lazy</tt> 属性来定义延迟初始化集合: </p><pre class="programlisting"><set name="names" table="NAMES" lazy="true"> <key column="group_id"/> <element column="NAME" type="string"/></set></pre><p> 在一些应用程序的体系结构中,特别是使用hibernate访问数据的结构, 代码可能会用在不用的应用层中, 可能没有办法保证当一个集合在初始化的时候, session仍然打开着。 这里有两个基本方法来解决这个问题: </p><div class="itemizedlist"><ul type="disc"><li><p> 在基于Web的应用程序中, 一个servlet过滤器可以用来在用户请求的完成之前来关闭<tt class="literal">Session</tt>。当然,这个地方(关闭session)严重依赖于你的应用程序结构中例外处理的正确性。在请求返回给用户之前关闭<tt class="literal">Session</tt>和结束事务是非常重要的,即使是在构建视图(译者注: 返回给用户的HTML页面)的时候发生了例外,也必须确保这一点。考虑到这一点,servlet过滤器可以保证能够操作这个<tt class="literal">Session</tt>。我们推荐使用一个<tt class="literal">ThreadLocal</tt>变量来保存当前的<tt class="literal">Session</tt>。 </p></li><li><p> 在一个有单独的商业层的应用程序中, 商业逻辑必须在返回之前“准备好”Web层所需要的所有集合。通常, 应用程序为每个Web层需要的集合调用<tt class="literal">Hibernate.initialize()</tt>(必须在Session被关闭之前调用)或者通过使用<tt class="literal">FETCH</tt>子句来明确获取到整个集合。 </p></li></ul></div><p> 你可以使用Hibernate Session API中的<tt class="literal">filter()</tt> 方法来在初始化之前得到集合的大小: </p><pre class="programlisting">( (Integer) s.filter( collection, "select count(*)" ).get(0) ).intValue()</pre><p> <tt class="literal">filter()</tt> 或者 <tt class="literal">createFilter()</tt>同样被用于有效的重新载入一个集合的子集而不需要载入整个集合。 </p></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="collections-s1-8a"></a>6.6. 集合排序(Sorted Collections)</h2></div></div><div></div></div><p> Hibernate支持实现<tt class="literal">java.util.SortedMap</tt>和<tt class="literal">java.util.SortedSet</tt>的集合。你必须在映射文件中指定一个比较器: </p><pre class="programlisting"><set name="aliases" table="person_aliases" sort="natural"> <key column="person"/> <element column="name" type="string"/></set><map name="holidays" sort="my.custom.HolidayComparator" lazy="true"> <key column="year_id"/> <index column="hol_name" type="string"/> <element column="hol_date type="date"/></map></pre><p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -