两个表通过主键来关联
就是一个表的主键依赖另一个表的主键,如果一个表里面没有数据,那么在另一关联他的表插入数据会报错。
如下:
配置文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lwf.hibernate.pojo" >
<class name="Person">
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" class="IdCard" constrained="true"></one-to-one>
</class>
<class name="IdCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
POJO
package com.lwf.hibernate.pojo;
public class Person {
private int id;
private String name;
private IdCard idCard;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.lwf.hibernate.pojo;
public class IdCard {
private int id;
private String cardNo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
}
生成的Sql语句:
create table IdCard (
id integer not null auto_increment,
cardNo varchar(255),
primary key (id)
)
create table Person (
id integer not null,
name varchar(255),
primary key (id)
)
alter table Person
add index FK8E488775694BC674 (id),
add constraint FK8E488775694BC674
foreign key (id)
references IdCard (id)
在数据库中产生两个表:
person表
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
idcard表
+--------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| cardNo | varchar(255) | YES | | NULL | |
+--------+--------------+------+-----+---------+----------------+
因为Person的主键关联于idcard的主键,所以必须先在idcard表中插入数据如
insert into idcard(cardNo) values('sfsddf');
产生数据;
+----+--------+
| id | cardNo |
+----+--------+
| 1 | sfsddf |
+----+--------+
下面再执行插入数据到person中。
insert into idcard(cardNo) values('sfsddf');
+----+------+
| id | name |
+----+------+
| 1 | dddl |
+----+------+
如果:
insert into person(id,name) values(3,'dddl');
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint f。。
ails (`hibernate`.`person`, CONSTRAINT `FK8E488775694BC674` FOREIGN KEY (`id`) R
EFERENCES `idcard` (`id`))
在使用hibernate进行插入时只需要
public static void main(String[] args) {
Session session = openSession();
IdCard idCard = new IdCard();
idCard.setCardNo("1121212");
Person person = new Person();
person.setIdCard(idCard);
person.setName("zhangshang");
session.save(person);
commitSession(session);
closeSession(session);
}
生成语句:
Hibernate:
/* insert com.lwf.hibernate.pojo.IdCard
*/ insert
into
IdCard
(cardNo)
values
(?)
Hibernate:
/* insert com.lwf.hibernate.pojo.Person
*/ insert
into
Person
(name, id)
values
(?, ?)
注意上面我们没有先sesssion.save(idCard);
在一对一关联中会自动先执行被关联对象的插入操作。这说明:
一对一关联默认了级联属性。
注意如果上面代码中把person.setIdCard(idCard);注释,那么会报NullPointerException
因为Person依赖IdCard为主键的,所以必须设置idCard属性
保存完之后加载
Person person = (Person)session.load(Person.class, 1);
System.out.println(person.getName());
System.out.println(person.getIdCard().getCardNo());
生成 语句
Hibernate:
/* load com.lwf.hibernate.pojo.Person */ select
person0_.id as id3_0_,
person0_.name as name3_0_
from
Person person0_
where
person0_.id=?
zhangshang
Hibernate:
/* load com.lwf.hibernate.pojo.IdCard */ select
idcard0_.id as id4_0_,
idcard0_.cardNo as cardNo4_0_
from
IdCard idcard0_
where
idcard0_.id=?
1121212
删除:
Person person = (Person)session.load(Person.class, 1);
session.delete(person);
将删除person表中id为1的列,删除不会删除与之关联的idCard表的的列。
如果:
IdCard idCard = (IdCard)session.load(IdCard.class, 3);
session.delete(idCard);
因为有Person表中的主键与之关联,所以删除报错,必须先删除Person表中对应的列。
双向关联:
上面我们加载的时候都是从person端加载,得到idCard
Person person = (Person)session.load(Person.class, 1);
System.out.println(person.getName());
System.out.println(person.getIdCard().getCardNo());
那么能不能从idCard端加载,得到person呢
试一下:
IdCard idCard = (IdCard)session.load(IdCard.class,1);
System.out.println(idCard.getPerson().getName());
输出结果:
报错
Hibernate:
/* load com.lwf.hibernate.pojo.IdCard */ select
idcard0_.id as id4_0_,
idcard0_.cardNo as cardNo4_0_
from
IdCard idcard0_
where
idcard0_.id=?
Exception in thread "main" java.lang.NullPointerException
at com.lwf.hibernate.test.TestPerson.main(TestPerson.java:19)
这里我们需要实现一对一的双向关联:
我们只要在idcard的映射文件中加入one-to-one 即可。
如:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lwf.hibernate.pojo" >
<class name="Person">
<id name="id">
<generator class="foreign">
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<one-to-one name="idCard" class="IdCard" constrained="true"></one-to-one>
</class>
<class name="IdCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person"></one-to-one>
</class>
</hibernate-mapping>
上面单向与双向双联我们只增加了:
<one-to-one name="person"></one-to-one>
对应person在IdCard Pojo类中定义属性:
private Person person;
并实现get与Set方法即可。
另一种一对一关联的方法是在配置文件中使用many-to-one,然后使用唯一属性
<many-to-one name="idCard" class="IdCard" column="idCardId" unique="true"></many-to-one>
这也就唯一外键关联,在家里即person表中的主键有id和idCardId两个字段,但idCardId关联idCard表的id字段,并且在person表中的idCardId是唯一的。
如我们把上例的配置文件改成:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lwf.hibernate.pojo" >
<class name="Person">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="idCard" class="IdCard" column="idCardId" unique="true"></many-to-one>
</class>
<class name="IdCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
对应的表结构:
mysql> desc person;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
| idCardId | int(11) | YES | UNI | NULL | |
+----------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)
mysql> desc idcard;
+--------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| cardNo | varchar(255) | YES | | NULL | |
+--------+--------------+------+-----+---------+----------------+
2 rows in set (0.02 sec)
保存
public static void save(Session session){
IdCard idCard = new IdCard();
idCard.setCardNo("1121212");
session.save(idCard);
Person person = new Person();
person.setIdCard(idCard);
person.setName("zhangshang");
session.save(person);
}
注意在使用many-to-one的时候默认级联属性为false,所以上面要先使用session.save(idCard);
再使用session.save(person);保存。
而上面的one-to-one的时候默认级联属性为true,所以不需要先session.save(idCard);
保存之后数据表如下:
mysql> select * from person;
+----+------------+----------+
| id | name | idCardId |
+----+------------+----------+
| 1 | zhangshang | 1 |
+----+------------+----------+
1 row in set (0.00 sec)
mysql> select * from idcard;
+----+---------+
| id | cardNo |
+----+---------+
| 1 | 1121212 |
+----+---------+
1 row in set (0.00 sec)
双向关联:
只要在idcard对应的配置中加入:
<one-to-one name="person" class="Person" property-ref="idCard"></one-to-one>
修改后的配置文件如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lwf.hibernate.map">
<class name="Person">
<id name="id">
<generator class="native"/>
</id>
<many-to-one name="idCard" column="idCardId" unique="true"/>
<property name="name"/>
</class>
<class name="IdCard">
<id name="id">
<generator class="native"/>
</id>
<property name="cardNo"/>
<one-to-one name="person" class="Person" property-ref="idCard"></one-to-one>
</class>
</hibernate-mapping>
测试从person取得idCard的数据:
Person person = (Person)session.load(Person.class, 2);
System.out.println(person.getName());
System.out.println(person.getIdCard().getCardNo());
测试双向,从idCard取得person的数据:
IdCard idCard = (IdCard)session.load(IdCard.class, 1);
System.out.println(idCard.getCardNo());
System.out.println(idCard.getPerson().getName());