hibernate关联映射-单向

关联关系映射通常情况是最难配置正确的。在这个部分中,我们从单向关系映射开始,然后考虑双向关系映射,逐步讲解典型的案例。在所有的例子中,我们都使将用 Person 和 Address。
我们根据映射关系是否涉及连接表以及多样性(multiplicity)来划分关联类型。
在传统的数据建模中,允许为 Null 值的外键被认为是一种不好的实践,因此我们所有的例子中都使用不允许为 Null 的外键。这并不是 Hibernate的 要求,即使你删除
掉不允许为 Null 的约束,Hibernate 映射一样可以工作的很好。
关联关系,多的一方持有一的一方的引用比如外键
8.2. 单向关联(Unidirectional associations)
8.2.1. 单向多对一外键关联(many-to-one)   方向: 多方(person)有一方(address)关联表的引用作为 属性,方向就是我有你的引用(get方法可以查询到你)
相当于一的一方为主表,多的一方为附表,附表有主表的引用。
单向 many-to-one 关联是最常见的单向关联关系。
模型:
多个人(Person)对应一个地址(Address)。
实体:
public class Personn1fk {
    private int personid;
    private String name;
    private int age;
    private Addressn1fk addressn1fk;
 
public class Addressn1fk {
    private int addressid;
    private String addressdetail;

映射:
<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  : address  单向多对一,在数据库中体现为  person还有address的 引用,多的一方肯定是有引用(比如外键)
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )

8.2.2. 一对一(One-to-one)
8.2.2.1
基于外键关联的单向一对一关联和单向多对一外键关联几乎是一样的。唯一的不同就是单向一对一关联中的外键字段具有唯一性约束
单向一对一的方向就是  person表有address的属性也就是getAddress()方法通过person找到address 事实上,单向1-1与N-1的实质是相同的,1-1是N-1的特例,单向1-1与N-1的映射配置也非常相似。只需要将原来的many-to-one元素增加unique="true"属性,用于表示N的一端也必须是唯一的,在N的一端增加了唯一的约束,即成为单向1-1。基于外键的单向1-1的配置将与无连接表N-1关联的many-to-one增加unique="true"属性即可。
模型:
一个人(Person)对应一个地址(Address)。
实体:
public class Person11fk {
    private int personid;
    private String name;
    private int age;
    private Address11fk address11fk;
 
public class Address11fk {
    private int addressid;
    private String addressdetail;
映射:
<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>
person  : address  单向一对一,在数据库中体现为  person还有address的 引用 并且是唯一的 1对1,简化后的多对一
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
8.2.2.2
基于主键关联的单向一对一关联通常使用一个特定的 id 生成器,1-1的关联可以基于主键关联,但基于主键关联的持久化类不能拥有自己的主键生成策略,它的主键由关联类负责生成。另外,另外,增加one-to-one元素来关联属性,必须为one-to-one元素增加constrained="true"属性,表明该类主键由关联类生成。
然而在这个例子中我们掉换了关联的方向

模型:一个人(Person)对应一个地址(Address)。
实体:
public class Person11pk {
    private int personid;
    private String name;
    private int age;
    private Address11pk address11pk;
 
public class Address11pk {
    private int addressid;
    private String addressdetail;
映射:
<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>
注:constrained="true"  则表明本表(address)存在外键与关联表(person)对应,并且关联表(person)中肯定存在对应的键与其对应。hibernate生成的sql将使用inner join. 另外该选项最关键的是影响save和delete的先后顺序。例如增加的时候,如果constainted=true,则会先增加关联表(person),然后增加本表(address)。删除的时候反之先删本表(address)再删关联表(person)。
address : person    单向一对一,在数据库中体现为 address的主键是引用person的的外键作为主键
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )

8.2.3. 一对多(one-to-many)
基于外键关联的单向一对多关联是一种很少见的情况,我们不推荐使用它。
相当于  多(address)的一方为主表,一(person)的一方为附表  person表用set集合来维护1对多的关系,不科学。通过1来找所有的多,效率低于多方找1方
因为关系一般有多的一端来维护 这样可以提高效率
一般来说都是用多的一方 通过set方法设置维护说明多的一方属于哪一个一,比如 多(address)的所属人是谁(person)通过address.setPerson(p);

//一对多关联
Set<Address> set = p.getAddress() ; set.add(address1) ; set.add(address2) ; session.save(address1) ; session.save(address2) ; 
模型:
一个人(Person)对应多个地址(Address),比如家庭地址、公司地址。
实体:
public class Person1nfk implements Serializable {
    private int personid;
    private String name;
    private int age;
    private Set addresses=new HashSet();
 
public class Address1nfk implements Serializable {
    private int addressid;
    private String addressdetail;
映射:
<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>
person  : address  单向,在数据库中体现为1对多。
create table Person ( personId bigint not null primary key )
create table Address ( addressId bigint not null primary key, personId bigint not null )
我们认为对于这种关联关系最好使用连接表。

8.3. 使用连接表的单向关联(Unidirectionalassociations with join tables)
8.3.1. 一对多(one-to-many)

基于连接表的单向一对多关联 应该优先被采用。请注意,通过指定unique="true",我们可以把多样性从多对多改变为一对多。
一方有多方的引用,可以通过set集合t获取多方信息
模型:一个人(Person)对应多个地址(Address),比如家庭地址、公司地址。
实体:
public class Person1ntab {
    private int personid;
    private String name;
    private int age;
    private Set addresses=new HashSet();
 
public class Address1nfk implements Serializable {
    private int addressid;
    private String addressdetail;

映射:
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<!--映射集合属性,PersonAddress是连接表表名--> <!--“column="personid"”确定Person表关联到连接表的外键列名-->
<set name="addresses" table="PersonAddress">
<key column="personId"/>
  <!--“unique="true"表示1-N,Person是1,Address是多”--> <!--“column="addressid"”关联PersonAddress表的Address对象的id在连接表中的列名-->
<many-to-many column="addressId" unique="true" class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
使用连接表 单向一对多person:address 数据库中体现为3张表:一方(person) 多方(address) 连接表 personAddress,
连接表中多方(address)还有1(person)引用。数据库只能表示1:n的关系,所以永远是多的一方持有1的引用
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 )

8.3.2. 多对一(many-to-one)
基于连接表的单向多对一关联在关联关系可选的情况下应用也很普遍。例如:

模型:多个人(Person)对应一个地址(Address)。
实体:
public class Personn1tab {
    private int personid;
    private String name;
    private int age;
    private Addressn1tab addressn1tab;
 
public class Addressn1tab {
    private int addressid;
    private String addressdetail;
映射:
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<!--使用join元素显式确定链接表-->
<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>
使用连接表 单向多对一 person : address 数据库中体现为3张表:多方(person) 一方(address) 连接表 personAddress,
连接表中多方(person)还有1方(address)引用。数据库只能表示1:n的关系,所以永远是多的一方持有1的引用
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 )

8.3.3. 一对一(One-to-one)
基于连接表的单向一对一关联也是可行的,但非常少见。

这种情况很少见,但Hibernate同样允许采用连接表关联1-1.有连接表的1-1同样只需要将连接表的N-1的many-to-one元素增加unique=“true”
模型:一个人(Person)对应一个地址(Address)。
实体:
public class Person11tab {
    private int personid;
    private String name;
    private int age;
    private Address11tab address11tab;
 
public class Address11tab {
    private int addressid;
    private String addressdetail;

映射:
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<join table="PersonAddress"
optional="true">
<!--映射1-1关联属性,其中unique=“true”属性确定为“1-1”-->
<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>
使用连接表 单向一对一 person : address 数据库中体现为3张表:多方(person) 一方(address) 连接表 personAddress,
连接表中多方(person)还有1方(address)引用。数据库只能表示1:n的关系,所以永远是多的一方持有1的引用。 这里是简化的连接表单向多对一
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 )

8.3.4. 多对多(many-to-many)
最后,这里是一个单向多对多关联的例子。
模型:一个人可对应多个地址,一个地址也可以对应多个人。
实体:
public class Personnn {
    private int personid;
    private String name;
    private int age;
    private Set addresses=new HashSet();
 
public class Addressnn {
    private int addressid;
    private String addressdetail;
映射:
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<!--映射集合属性,PersonAddress是连接表表名--><!--“column="personid"”确定Person表关联到连接表的外键列名-->
<set name="addresses" table="PersonAddress">
<key column="personId"/>
<!--“column="addressid"”关联Person表的Address对象的id在连接表中的列名-->
<many-to-many column="addressId"
class="Address"/>
</set>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
使用连接表 单向多对多 person : address 数据库中体现为3张表: 连接表 personAddress,
连接表中互相引用。数据库只能表示1:n的关系,所以永远是多的一方持有1的引用。 连接表等于是2个1:n的关系。
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 )8.4. 双向关联(Bidirectional associations)


8.4.1. 一对多(one to many)/多对一(many to one)
双向多对一关联 是最常见的关联关系。下面的例子解释了这种标准的父/子关联关系。
模型:一个人(Person)对应多个地址(Address)。
实体:

<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>
create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
如果你使用 List(或者其他 有序集合类),你需要设置 外键对应的 key 列为 not null。Hibernate将从集合端管理关联,维护每个元素的索引,并通过设置 update="false" 和 insert="false" 来对另一端反向操作。
<class name="Person">
<id name="id"/>
<many-to-one name="address"
column="addressId"
not-null="true"
insert="false"
update="false"/>
</class>

<class name="Address">
<id name="id"/>
<list name="people">
<key column="addressId" not-null="true"/>
<list-index column="peopleIdx"/>
<one-to-many class="Person"/>
</list>
</class>
假若集合映射的 <key> 元素对应的底层外键字段是 NOT NULL 的,那么为这一 key 元素定义 notnull="
true" 是很重要的。不要仅仅为可能的嵌套 <column>元素定义 not-null="true",<key> 元素
也是需要的。

8.4.2. 一对一(One-to-one)
基于外键关联的双向一对一关联也很常见。

<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>
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )

基于主键关联的一对一关联需要使用特定的 id 生成器:
<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>
create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )

8.5. 使用连接表的双向关联(Bidirectional associationswith join tables)
8.5.1. 一对多(one to many)/多对一(many to one)

下面是一个 基于连接表的双向一对多关联的例子。注意 inverse="true" 可以出现在关联的任意一端,即 collection 端或者 join 端。
<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>
连接表中多方(address)还有1方(person)引用
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 )

8.5.2. 一对一(one to one)
基于连接表的双向一对一关联也是可行的,但极为罕见。

<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="person"
column="personId"
not-null="true"
unique="true"/>
</join>
</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 )

8.5.3. 多对多(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>
<set name="people" inverse="true" table="PersonAddress">
<key column="addressId"/>
<many-to-many column="personId"
class="Person"/>
</set>
</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 )

http://lavasoft.blog.51cto.com/62575/39398这篇博客有详细代码解释
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值