hibernate一对一映射
一、建立两个对象:一个Person,一个身份证
这两个类是一对一的映射
二、建立实体之间的关系 :
1、首先从Person的角度,先看看这个人,要知道他的身分证号是什么,所以要持有一个身分证的引用。
反过来,拿到身分证的时候,要知道这个人。所以在 IdCard中要持有Person的引用。
所谓的单双向,是指从一个对象可以访问到另一个对象,从另一个对象访问不到它。而双向它们就可以互相访问了。
从Person可以看到IdCard,从IdCard可以看到Person.这叫做双向。
我们先看它的单向。
如果只看单向,则Person要持有IdCard的引用。Person IdCard这两个对象之间是有有关系的,所以有一个箭头连接两者。
所以表面看它们的关系和用户和组的关系似乎是一样的。所以必须通过映射标签才能区别两者。
2、一对一关联映射有两种:一种是主键关联,一种是外键关联。
主键关联就是我们的两个实体而生成的两个表的主键相同。也就是说,如果IdCard这个表里有一个主键是1,则Person这个表里也有一个主键是1.这样就不用加任何字段让主键一致。
主键关联不用增加字段,还是原来的字段就可以了。
因为person引用了idCard,所以idCard一定先有值。
三、如何映射实现主键一致。
一、新建项目hibernate_one2one_pk_1:单向关联
二、建立实体类
1、IdCard类。
package com.bjsxt.hibernate;
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;
}
}
2、Person.class
package com.bjsxt.hibernate;
public class Person {
private int id;
private String name;
IdCard idCard;
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
三、实体有了之后,要建立映射文件,将两者的关系建立起来
1、选建立简单的。就 是IdCard.hbm.xml文件
<?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>
<class name="com.bjsxt.hibernate.IdCard" table="t_idcard" >
<id name="id">
<generator class="native"></generator>
</id>
<property name="cardNo"/>
</class>
</hibernate-mapping>
2、映射Person,建立Person.hbm.xml文件
Person一端的主键来源于IdCard一端的主键。Person的主键以外键的形式参照IdCard的主键。
foreign主键生成策略,使用另外一个相关联的对象的标识符,通常和<one-to-one>联合起来用。Person会把IdCard的标识拿过来,它用。
<generator>
<param name="property">idCard</pram>
</generaor>
上述含义是:在ForeignGenerator.class类中,有一个configure()方法,这个方法要读取“perperty"的值,然后再拿到值的id来用。所以name必须用property.
<one-to-one>加载的含义是:将Person中的1与IdCard中的1对比,如果相同,则把IdCard的值拿过来。
Person.hmbm.xml 文件内容如下:
<?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>
<class name="com.bjsxt.hibernate.Person" table="t_person">
<id name="id">
<!--我们的应该一对一的映射,而且不能加外键
所以主键的生成策略不能是native.因为这种方式是自 增的,就没有参照IdCard类的主键
所以生成策略要改成foreign方式,就是参照外部的
所以Person表的主键是不能自增的 -->
<!-- 这种生成策略要加参数,名字就是peroperty.是固定的 -->
<generator class="foreign">
<!-- 标签中的值是指明标识来源于谁
foreign方式,标识来源于关联对象的标识,
所以来源对象要指定
所以拿来Person类的属性idCard作为id的标识 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!-- one-to-one指的是如何加载它的引用对象
外键约束要设为true-->
<one-to-one name="idCard" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
四、修改 hiberante.cfg.xml文件
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory >
<!-- 数据库改成hibernate_session -->
<property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_one2one_pk_1</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="com/bjsxt/hibernate/IdCard.hbm.xml"/>
<mapping resource="com/bjsxt/hibernate/Person.hbm.xml"/>
</session-factory>
</hibernate-configuration>
五、在MysqL 中创建数据库
create database hibernate_one2one_pk_1;
user hiberante_one2one_pk_1;
六、执行ExportDB.class 文件,将对象模型导出表
package com.bjsxt.hibernate;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
//这个类写完之后,以后就再也不用写了。
//这个类就是把hibernate的配置文件,转换成DDL。
public class ExportDB {
public static void main(String[] args){
//读取hibernate.cfg.xml文件
Configuration cfg=new Configuration().configure(); //hibernate中的一个api,是Configuraton。引入时,将光标定位在Configuration上
//右击,选择"Source"命令的"Add Import"命令,找到hibernate的Configuration。
//它是用来读取hibernate中的配置文件的。即hibernate.cfg.xml文件。(相当于Struts中的
//ActionServlet)
//这样直接写 Configuration cfg=new Configuration();会有问题,因为
//hibernate有两个配置文件,一个是property类型的,一个是xml类型的,这样
//new完,就会默认的读取property类型的配置文件,这样就会有问题。所以必须加上它的一个
//方法configure()。
//hibernate中有一个工具类,叫SchemaExport,这个工具类需要传送configuration.
//这个对象就把我们的类生成(导成)表出来。
SchemaExport export=new SchemaExport(cfg);
export.create(true, true); //script是判断生成不生成,它实际是生成ddl.
//这两个参数都设置成true就可以了。
//这个方法的具体含义可以直接看它的api。
//或者关联上它的源代码,可以在create上,点击F3,
//选择"Attach Resource",选择“External File",
//再找到F:/java program/Hibernate相关资料/hibernate-3.2.0.ga,就关联上了。
//export.create(..)是拿到对象,直接生成就可以了。
}
}
控制台输出:
drop table if exists t_idcard
drop table if exists t_person
create table t_idcard (id integer not null auto_increment, cardNo varchar(255), primary key (id))
create table t_person (id integer not null, name varchar(255), primary key (id))
//t_person中没有加入任何字段,还是原来的
alter table t_person add index FK785BED809AC0D5D6 (id), add constraint FK785BED809AC0D5D6 foreign key (id) references t_idcard (id)//这条语句是建立两者的关系。之所以生成这样的语句就是因为加上了constraint约束,加上这个约束后就加上了这条语句。
语句解释为:t_person 中的id 作为外键,参照了t_idCard中的id.
七、写单元测试类:
package com.bjsxt.hibernate;
import org.hibernate.Session;
import junit.framework.TestCase;
public class One2OneTest extends TestCase {
public void testSave1(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard=new IdCard();
idCard.setCardNo("8888888");
Person person=new Person();
person.setName("菜10");
person.setIdCard(idCard);
session.save(person);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
控制台显示:
insert into t_idcard (cardNo) values (?)
insert into t_person (name, id) values (?, ?)
八、测试加载,看一下能不能将关系模型中的数据拿出来,然后放到对象里面。
OR映射的宗质就是像对象模型里面的东西存到关系模型里面。再将关系模型里面的东西拿出来放到对象里面。以前这些东西是我们自己做的,就像写的DAO一样的。
one-to-one标签指的是如何加载关联对象或是引用对象。
原理就是先找到t_person表中主键为4的记录,然后到t_idcard 表,找主键为4的,然后将它的carNo 加上 来,放到IdCard 里面,所以可以看到正确的结果。
测试代码 如下:
package com.bjsxt.hibernate;
import junit.framework.TestCase;
public class One2OneTest extends TestCase {
public void testLoad(){
Session session=null;
try{
session=HibernateUtils.getSession();
session.beginTransaction();
Person person=(Person)session.get(Person.class,Integer.valueOf("4"));
System.out.println("person.getName()="+person.getName());
System.out.println("person.getIdCard().getCardNo="+person.getIdCard().getCardNo());
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
结果:
select person0_.id as id1_0_, person0_.name as name1_0_ from t_person person0_ where person0_.id=?
person.getName()=菜10
select idcard0_.id as id0_0_, idcard0_.cardNo as cardNo0_0_ from t_idcard idcard0_ where idcard0_.id=?
person.getIdCard().getCardNo=8888888
九、readme.txt文件
hibernate一对一主键关联映射(单向关联Person------>IdCard)
一对一主键关联映射是让两个实体类对象的id保持相同。这样就可以避免
多余的字段被创建
具体映射:
<id name="id">
<!--person的主键来源于idCard,也就是共享 idCArd的主键-->
。。。。。
<!-- one-to-one 标签的含义,只是hiberante怎么加载它的关联对象,
对于我们来说,就是idCard .默认根据主键加载
constrained="true" 的含义表明当前主键上存在一个约束
person的主键作为外键参照idCard.-->