Hibernate ORM框架——续第二章:Hibernate映射关系:单向关联
一:课堂笔记
**********单表映射*************** 1.只有一个实体类映射一个表 2.有一个实体类+ 一个或者多个值类型,合在一起 映射为一个表 **********多表映射*************** 定义:类有多个映射为多个表
**********数据库层面,如ORM无关************** 2个表之间要建立关系?该如何做?有多少种方法 假定有2个表,分别为A,B 3种关系 a)主键关联:A表的主键对应B表的主键,(一对一的关系) 在数据库种如何建立这种关系? 假定A做为主表,在B表里面的某个字段既是主键也是外键
b)外键关联: c)连接表关联(中间表关联): 中间表关联既可以做一对一,也可以做一对多,也可以做多对多关联 但实际项目中,出现中间表关联的时候,一般就是多对多 多对多关系,在数据库层面本质上“不支持”。 一般是把多对多关系拆分为2个一对多 **********代码层面************** 类与类之间有什么关系?有纵向的继承关系 横向的“关联” 比如下面有一个关联关系 public class Person{ private Address addr } 在类层面关系是2方面 public class Address{ private Person p } 除了上面类与类之间有一对一的关系,还有一对多的关系
**********映射配置的整体情况********
除了多对多是利用中间表的形式来做映射,其它所有的情况
都是利用外键的方式来配置的
************ 由于类之间有单,双向的问题,也有一对一,一对多的问题 表之间建立关系又有三种类型。 在课程中,只学: 单向关系:指A表可以查到B表的东西,但B表不能查到A表的东西
多对一
一对多
一对一
双向关系: 一对一 一对多 多对一 多对多
二、多对一的关系(代码)
(1)hibernate.cfg,xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property> <property name="connection.username">myuser</property> <property name="connection.password">123</property> <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property> <!-- <property name="hbm2ddl.auto">create</property> --> <property name="show_sql">true</property> <property name="format_sql">true</property> <mapping resource="entity/StudentMapping.xml"/> <mapping resource="entity/ClassInfoMapping.xml"/> </session-factory> </hibernate-configuration>
(2.1)实体1
package entity; public class ClassInfo { private String cno; private String cname;
/*set/get方法省略*/
}
(2.2)实体2
package entity; public class Student { private String sno; private String sname; //单向关联:多对一 //学生:班级=N:1-->一般在多的这边写外键 //所以classinfo的映射文件不需要改,只需要改Student的映射文件 private ClassInfo cinfo;
/*set/get方法省略*/
}
(3.1)班级实体映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="entity"> <class name="ClassInfo" table="classinfo"> <id name="cno" column="cid"> <generator class="assigned"></generator> </id> <property name="cname"></property> </class> </hibernate-mapping>
(3.2)学生实体映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="entity"> <class name="Student" table="student"> <id name="sno" column="sid"> <generator class="assigned"></generator> </id> <property name="sname"></property> <!-- 单向关联:多对一 学生:班级=N:1 一般在多的这边写外键 所以classinfo的映射文件不需要改,只需要改Student的映射文件 column="rcno"的意思为:设定持久化类属性对应的表的外键 --> <many-to-one name="cinfo" column="rcno"></many-to-one> <!-- 通过cinfo的持久化类属性的名称,系统会自动找到对应的ClassInfoMapping映射文件 --> </class> </hibernate-mapping>
(4)HibernateUtil工具类不变
(5)test包的Main.java
package test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import entity.ClassInfo; import entity.Student; import util.HibernateUtil; public class Main { public static void main(String[] args) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); /*先创建一个班级*/ ClassInfo cinfo1 = new ClassInfo(); cinfo1.setCno("1"); cinfo1.setCname("132"); s.save(cinfo1); /*创建两个学生共用132班*/ Student stu1 = new Student(); stu1.setSno("1"); stu1.setSname("lss"); stu1.setCinfo(cinfo1); s.save(stu1); Student stu2 = new Student(); stu2.setSno("2"); stu2.setSname("zss"); stu2.setCinfo(s.get(ClassInfo.class, "1")); s.save(stu2); tx.commit(); s.close(); //不论是多对一的关联关系还是一对多的关联关系,所创建出来的数据库代码都是一样的 //说明:此方法同时创建两张表 //同时创建两张表 /*Hibernate: create table classinfo ( cid varchar2(255 char) not null, cname varchar2(255 char), primary key (cid) ) Hibernate: create table student ( sid varchar2(255 char) not null, sname varchar2(255 char), rcno varchar2(255 char), primary key (sid) ) Hibernate: alter table student add constraint FKlj3is017vndc46gtd2cpyrk0l foreign key (rcno) references classinfo*/ } }
三、一对多的关系(代码)
(1)hibernate.cfg,xml配置文件:不变
(2.1)实体1
package entity; import java.util.Set; public class ClassInfo { private String cno; private String cname; //这里表明一个班级有多个学生 //用Set集合的原因,是因为Set里面不能放重复的数据 //现实的情况是没有2个完全一样的人(学生) //Set最好是用接口声明,而不要用具体的Set接口的实现类来声明 //单向关联:一对多 //班级:学生=1:N //所以Student的映射文件不需要改,只需要改classinfo的映射文件 private Set<Student> sinfo;
/*set/get方法省略*/
}
(2.2)实体2
package entity; public class Student { private String sno; private String sname;
/*set/get方法省略*/
}
(3.1)班级实体映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="entity"> <class name="ClassInfo" table="classinfo"> <id name="cno" column="cid"> <generator class="assigned"></generator> </id> <property name="cname"></property>
<!--
set name="sinfo":持久化类的属性名
key column="rsno":外键名称
one-to-many class="Student":类名
-->
<set name="sinfo"> <key column="rsno"></key> <one-to-many class="Student"/> </set> </class> </hibernate-mapping>
(3.2)学生实体映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="entity"> <class name="Student" table="student"> <id name="sno" column="sid"> <generator class="assigned"></generator> </id> <property name="sname"></property> </class> </hibernate-mapping>
(4)HibernateUtil工具类不变
(5)test包的Main.java
package test; import java.util.HashSet; import java.util.Set; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import entity.ClassInfo; import entity.Student; import util.HibernateUtil; public class Main { public static void main(String[] args) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); ClassInfo cinfo1 = new ClassInfo(); cinfo1.setCno("1"); cinfo1.setCname("132"); Student stu1 = new Student(); stu1.setSno("1"); stu1.setSname("lss"); s.save(stu1); Student stu2 = new Student(); stu2.setSno("2"); stu2.setSname("zss"); s.save(stu2); Set<Student> set = new HashSet<Student>(); set.add(stu1); set.add(stu2); cinfo1.setSinfo(set); s.save(cinfo1); tx.commit(); s.close(); //说明:此方法同时创建两张表 //同时创建两张表 /*Hibernate: create table classinfo ( cid varchar2(255 char) not null, cname varchar2(255 char), primary key (cid) ) Hibernate: create table student ( sid varchar2(255 char) not null, sname varchar2(255 char), rsno varchar2(255 char), primary key (sid) ) Hibernate: alter table student add constraint FK2gv2uqo8k36ytnfwv1y007t8i foreign key (rsno) references classinfo*/ } }
四、一对一的关系(代码):在多对一的基础上改,多加一个唯一键
(1)hibernate.cfg,xml配置文件:不变
(2.1)实体1
package entity; public class ClassInfo { private String cno; private String cname; /*set/get方法省略*/ }
(2.2)实体2
package entity; public class Student { private String sno; private String sname; //单向关联:多对一 //学生:班级=N:1-->一般在多的这边写外键 //所以classinfo的映射文件不需要改,只需要改Student的映射文件 private ClassInfo cinfo;
/*set/get方法省略*/
}
(3.1)班级实体映射文件:不变
(3.2)学生实体映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="entity"> <class name="Student" table="student"> <id name="sno" column="sid"> <generator class="assigned"></generator> </id> <property name="sname"></property> <!-- 单向关联:多对一 学生:班级=N:1 一般在多的这边写外键 所以classinfo的映射文件不需要改,只需要改Student的映射文件 column="rcno"的意思为:设定持久化类属性对应的表的外键 在以上的基础上加一个唯一约束键 --> <many-to-one name="cinfo" column="rcno" unique="true"></many-to-one> <!-- 通过cinfo的持久化类属性的名称,系统会自动找到对应的ClassInfoMapping映射文件 --> </class> </hibernate-mapping>
(4)HibernateUtil工具类不变
(5)test包的Main.java
package test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import entity.ClassInfo; import entity.Student; import util.HibernateUtil; public class Main { public static void main(String[] args) { SessionFactory sf = HibernateUtil.getSessionFactory(); Session s = sf.openSession(); Transaction tx = s.beginTransaction(); //一个班级只有一个学生,一个学生只能在一个班级内 //先创建一个班级1 ClassInfo cinfo1 = new ClassInfo(); cinfo1.setCno("1"); cinfo1.setCname("132"); s.save(cinfo1); //先创建一个班级2 ClassInfo cinfo2 = new ClassInfo(); cinfo2.setCno("2"); cinfo2.setCname("133"); s.save(cinfo2); //创建一个学生1 Student stu1 = new Student(); stu1.setSno("1"); stu1.setSname("lss"); stu1.setCinfo(cinfo1); s.save(stu1); //创建一个学生2 Student stu2 = new Student(); stu2.setSno("2"); stu2.setSname("zss"); stu2.setCinfo(cinfo2); s.save(stu2); tx.commit(); s.close(); //说明:数据库中,在多对一的关联关系或者一对多的关联关系的基础上多了一个唯一键约束 //同时创建两张表 /*Hibernate: create table student ( sid varchar2(255 char) not null, sname varchar2(255 char), rcno varchar2(255 char), primary key (sid) ) Hibernate: alter table student add constraint UK_f3b53nwj62n7h3a8rrn4tbuvu unique (rcno) Hibernate: alter table student add constraint FKlj3is017vndc46gtd2cpyrk0l foreign key (rcno) references classinfo*/ } }
五、个人总结
/*以上个人整理笔记,如果有误或者有不懂的地方,欢迎评论与指出*/