502 lines
16 KiB
XML
502 lines
16 KiB
XML
<chapter id="associations">
|
||
|
||
<title>关联关系映射</title>
|
||
|
||
<sect1 id="assoc-intro" revision="1">
|
||
<title>介绍</title>
|
||
|
||
<para>
|
||
关联关系映射通常情况是最难配置正确的。在这个部分中,我们从单向关系映射开始,然后考虑双向关系映射,由浅至深讲述一遍典型的案例。在所有的例子中,我们都使用 <literal>Person</literal>和<literal>Address</literal>。
|
||
</para>
|
||
|
||
<para>
|
||
我们根据映射关系是否涉及连接表以及多样性来划分关联类型。
|
||
</para>
|
||
|
||
<para>
|
||
在传统的数据建模中,允许为Null值的外键被认为是一种不好的实践,因此我们所有的例子中都使用不允许为Null的外键。这并不是Hibernate的要求,即使你删除掉不允许为Null的约束,Hibernate映射一样可以工作的很好。
|
||
</para>
|
||
|
||
</sect1>
|
||
|
||
<sect1 id="assoc-unidirectional" revision="1">
|
||
<title>单向关联(Unidirectional associations)</title>
|
||
|
||
<sect2 id="assoc-unidirectional-m21">
|
||
<title>多对一(many to one)</title>
|
||
|
||
<para>
|
||
<emphasis>单向many-to-one关联</emphasis>是最常见的单向关联关系。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
not-null="true"/>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-unidirectional-121">
|
||
<title>一对一(one to one)</title>
|
||
|
||
<para>
|
||
<emphasis>基于外键关联的单向一对一关联</emphasis>和<emphasis>单向多对一关联</emphasis>几乎是一样的。唯一的不同就是单向一对一关联中的外键字段具有唯一性约束。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
unique="true"
|
||
not-null="true"/>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
<para>
|
||
<emphasis>基于主键关联的单向一对一关联</emphasis>通常使用一个特定的id生成器。(请注意,在这个例子中我们掉换了关联的方向。)
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="personId">
|
||
<generator class="foreign">
|
||
<param name="property">person</param>
|
||
</generator>
|
||
</id>
|
||
<one-to-one name="person" constrained="true"/>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table Address ( personId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-unidirectional-12m">
|
||
<title>一对多(one to many)</title>
|
||
|
||
<para>
|
||
<emphasis>基于外键关联的单向一对多关联</emphasis>是一种很少见的情况,并不推荐使用。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="addresses">
|
||
<key column="personId"
|
||
not-null="true"/>
|
||
<one-to-many class="Address"/>
|
||
</set>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table Address ( addressId bigint not null primary key, personId bigint not null )
|
||
]]></programlisting>
|
||
|
||
<para>
|
||
我们认为对于这种关联关系最好使用连接表。
|
||
</para>
|
||
|
||
</sect2>
|
||
|
||
</sect1>
|
||
|
||
<sect1 id="assoc-unidirectional-join" revision="1">
|
||
<title>使用连接表的单向关联(Unidirectional associations with join tables)</title>
|
||
|
||
<sect2 id="assoc-unidirectional-join-12m">
|
||
<title>一对多(one to many)</title>
|
||
|
||
<para>
|
||
<emphasis>基于连接表的单向一对多关联</emphasis> 应该优先被采用。请注意,通过指定<literal>unique="true"</literal>,我们可以把多样性从多对多改变为一对多。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="addresses" table="PersonAddress">
|
||
<key column="personId"/>
|
||
<many-to-many column="addressId"
|
||
unique="true"
|
||
class="Address"/>
|
||
</set>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId not null, addressId bigint not null primary key )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-unidirectional-join-m21">
|
||
<title>多对一(many to one)</title>
|
||
|
||
<para>
|
||
<emphasis>基于连接表的单向多对一关联</emphasis>在关联关系可选的情况下应用也很普遍。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<join table="PersonAddress"
|
||
optional="true">
|
||
<key column="personId" unique="true"/>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
not-null="true"/>
|
||
</join>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-unidirectional-join-121">
|
||
<title>一对一(one to one)</title>
|
||
|
||
<para>
|
||
<emphasis>基于连接表的单向一对一关联</emphasis>非常少见,但也是可行的。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<join table="PersonAddress"
|
||
optional="true">
|
||
<key column="personId"
|
||
unique="true"/>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
not-null="true"
|
||
unique="true"/>
|
||
</join>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-unidirectional-join-m2m">
|
||
<title>多对多(many to many)</title>
|
||
|
||
<para>
|
||
最后,还有 <emphasis>单向多对多关联</emphasis>.
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="addresses" table="PersonAddress">
|
||
<key column="personId"/>
|
||
<many-to-many column="addressId"
|
||
class="Address"/>
|
||
</set>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
</sect1>
|
||
|
||
<sect1 id="assoc-bidirectional" revision="1">
|
||
<title>双向关联(Bidirectional associations)</title>
|
||
|
||
<sect2 id="assoc-bidirectional-m21">
|
||
<title>一对多(one to many) / 多对一(many to one)</title>
|
||
|
||
<para>
|
||
<emphasis>双向多对一关联</emphasis> 是最常见的关联关系。(这也是标准的父/子关联关系。)
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
not-null="true"/>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="people" inverse="true">
|
||
<key column="addressId"/>
|
||
<one-to-many class="Person"/>
|
||
</set>
|
||
</class>]]></programlisting>
|
||
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-bidirectional-121">
|
||
<title>一对一(one to one)</title>
|
||
|
||
<para>
|
||
<emphasis>基于外键关联的双向一对一关联</emphasis>也很常见。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
unique="true"
|
||
not-null="true"/>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<one-to-one name="person"
|
||
property-ref="address"/>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
<para>
|
||
<emphasis>基于主键关联的一对一关联</emphasis>需要使用特定的id生成器。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<one-to-one name="address"/>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="personId">
|
||
<generator class="foreign">
|
||
<param name="property">person</param>
|
||
</generator>
|
||
</id>
|
||
<one-to-one name="person"
|
||
constrained="true"/>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table Address ( personId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
</sect1>
|
||
|
||
<sect1 id="assoc-bidirectional-join" revision="1">
|
||
<title>使用连接表的双向关联(Bidirectional associations with join tables)</title>
|
||
|
||
<sect2 id="assoc-bidirectional-join-12m">
|
||
<title>一对多(one to many) /多对一( many to one)</title>
|
||
|
||
<para>
|
||
<emphasis>基于连接表的双向一对多关联</emphasis>。注意<literal>inverse="true"</literal>可以出现在关联的任意一端,即collection端或者join端。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="addresses"
|
||
table="PersonAddress">
|
||
<key column="personId"/>
|
||
<many-to-many column="addressId"
|
||
unique="true"
|
||
class="Address"/>
|
||
</set>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<join table="PersonAddress"
|
||
inverse="true"
|
||
optional="true">
|
||
<key column="addressId"/>
|
||
<many-to-one name="person"
|
||
column="personId"
|
||
not-null="true"/>
|
||
</join>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-bidirectional-join-121">
|
||
<title>一对一(one to one)</title>
|
||
|
||
<para>
|
||
<emphasis>基于连接表的双向一对一关联</emphasis>极为罕见,但也是可行的。
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<join table="PersonAddress"
|
||
optional="true">
|
||
<key column="personId"
|
||
unique="true"/>
|
||
<many-to-one name="address"
|
||
column="addressId"
|
||
not-null="true"
|
||
unique="true"/>
|
||
</join>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<join table="PersonAddress"
|
||
optional="true"
|
||
inverse="true">
|
||
<key column="addressId"
|
||
unique="true"/>
|
||
<many-to-one name="address"
|
||
column="personId"
|
||
not-null="true"
|
||
unique="true"/>
|
||
</join>
|
||
</class>]]></programlisting>
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
<sect2 id="assoc-bidirectional-join-m2m">
|
||
<title>多对多(many to many)</title>
|
||
|
||
<para>
|
||
最后,还有 <emphasis>双向多对多关联</emphasis>.
|
||
</para>
|
||
|
||
<programlisting><![CDATA[<class name="Person">
|
||
<id name="id" column="personId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="addresses">
|
||
<key column="personId"/>
|
||
<many-to-many column="addressId"
|
||
class="Address"/>
|
||
</set>
|
||
</class>
|
||
|
||
<class name="Address">
|
||
<id name="id" column="addressId">
|
||
<generator class="native"/>
|
||
</id>
|
||
<set name="people" inverse="true">
|
||
<key column="addressId"/>
|
||
<many-to-many column="personId"
|
||
class="Person"/>
|
||
</set>
|
||
</class>]]></programlisting>
|
||
|
||
<programlisting><![CDATA[
|
||
create table Person ( personId bigint not null primary key )
|
||
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
|
||
create table Address ( addressId bigint not null primary key )
|
||
]]></programlisting>
|
||
|
||
</sect2>
|
||
|
||
</sect1>
|
||
|
||
|
||
</chapter>
|
||
|