关联关系映射通常情况是最难配置正确的。在这个部分中,我们从单向关系映射开始,然后考虑双向关系映射,由浅至深讲述一遍典型的案例。在所有的例子中,我们都使用 Person
和Address
。
我们根据映射关系是否涉及连接表以及多样性来划分关联类型。
单向many-to-one关联是最常见的单向关联关系。
- <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>
多的一方(Person),有一个字段(addressId)指向一的一方(Address)
create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )一对一(one to one)
1、基于外键关联的单向一对一关联和单向多对一关联几乎是一样的。
唯一的不同就是单向一对一关联中的外键字段具有唯一性约束。 让多的一方变为 unique即可
- <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>
create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )addressId 为unique,所以只能属于一个 person2、基于主键关联的单向一对一关联 通常使用一个特定的id生成器。(请注意,在这个例子中我们掉换了关联的方向。)(Address 持有Person对象)
- <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>
Address 没有自己的id生成器,只能用 Person类的主键。
create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )一对多(one to many)
1、基于外键关联的单向一对多关联
是一种很少见的情况,并不推荐使用。一对多,需要在一的一方有 set<Address> addresses 属性
在多的一方(Address) 增加了一个 指向一方(Person)的列(personId)
- <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>
create table Person ( personId bigint not null primary key ) create table Address ( addressId bigint not null primary key, personId bigint not null )我们认为对于这种关联关系最好使用连接表。
注意:列都是增加在多的一方 *-to-many class="**"二、使用连接表的单向关联
(Unidirectional associations with join tables)
一对多(one to many)
基于连接表的单向一对多关联 应该优先被采用。
请注意,通过指定
unique="true"
,我们可以把多样性从多对多改变为一对多。(many to one 指定unique=“true”,把多样性从多对一变为一对一
many to many 指定unique=“true”,把多样性从多对多变为 一对多)都把第一个many变为one
- <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>
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 )
多对一(many to one)
1、基于连接表的单向多对一关联
在关联关系可选的情况下应用也很普遍。
- <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>
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 )一对一(one to one)
1、基于连接表的单向一对一关联
非常少见,但也是可行的。
- <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>
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 )多对多(many to many)
最后,还有 单向多对多关联.
- <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>
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 )总结:
*-to-one 都没有指定 class 属性。*-to-many 都指定了 class 属性
<many-to-one name="address" -->属性 column="addressId"--->本表中增加 addressId 列 not-null="true"/> --->不为空<one-to-one name="person" constrained="true"/> -->Address类中的 person属性<one-to-many class="Address"/><many-to-many column="addressId" <one-to-many>,<many-to-many>都作为set的子元素出现, 因为是 to-many,对多。 他们都不是在本表中增加字段,要么在多方增加字段(无连接表时(通过<set>中的<key column> 添加),要么在连接表中增加字段(column属性添加))。 <one-to-many>很少用,只能用在无连接表的 一对多中,有连接表时是<many-to-many>。 都必须指定class属性,都紧跟着<key> <many-to-many> 可以指定columu属性,在连接表中可以指定字段名<one-to-many 依靠key指定属性,只用在无连接表中。many-to-many 在<set 中指定table名many-to-one 在<join table> 中指定table名 有连接表时 要么是 <many-to-many> 要么是<many-to-one>,通过增加或取消 unique属性,映射出多对多,一对多; 多对一,一对一;<many-to-many> 可以对应 多对多,还可以对应 一对多。<many-to-one> 可以对应 多对一,还可以对应 一对一。有连接表 都有 <key column="" > 指定一个列名