关联关系映射分为:
1. 一对多关系映射
2. 多对多关系映射
3. 一对一关系映射
hibernate中关联关系映射有分单向和双向,单向映射则为一方来维护关系,双向映射则为一起维护关系(简单来说就是由老婆保管财产或者由双方一起保管财产的区别)下方例子均为双向,单向只需要把一方的映射删除就OK。
一、一对多关系映射
实体类
public class Customer {
private Integer cid; private String cname;
//一对多:一个客户(当前客户) 拥有 【多个订单】 // * 需要容器存放多个值,一般建议Set (不重复、无序) // * 参考集合:List、Map、Array等 // ** 建议实例化--使用方便 private Set<Order> orderSet = new HashSet<Order>(); |
public class Order { private Integer xid; private String price;
//多对一:多个订单属于【一个客户】 private Customer customer; |
配置文件
Customer.hbm.xml
<class name="com.itheima.b_onetomany.Customer" table="t_customer"> <id name="cid"> <generator class="native"></generator> </id> <property name="cname"></property>
<!-- 一对多:一个客户(当前客户) 拥有 【多个订单】 1 确定容器 set <set> 2 name确定对象属性名 3 确定从表外键的名称 4 确定关系,及另一个对象的类型 注意: 在hibernate中可以只进行单向配置 每一个配置项都可以完整的描述彼此关系。 一般情况采用双向配置,双方都可以完成描述表与表之间关系。 --> <!-- 一对多:一个客户(当前客户) 拥有 【多个订单】 --> <set name="orderSet" cascade="delete-orphan"> <key column="customer_id"></key> <one-to-many class="com.itheima.b_onetomany.Order"/> </set> </class> |
Order.hbm.xml
<class name="com.itheima.b_onetomany.Order" table="t_order"> <id name="xid"> <generator class="native"></generator> </id> <property name="price"></property>
<!-- 多对一:多个订单属于【一个客户】 * name 确定属性名称 * class 确定自定义类型 * column 确定从表的外键名称 --> <many-to-one name="customer" class="com.itheima.b_onetomany.Customer" column="customer_id"></many-to-one>
</class> |
一对多操作
保存客户
@Test public void demo01(){ // 1 创建客户,并保存客户--成功 Session session = factory.openSession(); session.beginTransaction();
Customer customer = new Customer(); customer.setCname("田志成");
session.save(customer);
session.getTransaction().commit(); session.close(); } |
保存订单
@Test public void demo02(){ // 2 创建订单,保存订单--成功,外键为null Session session = factory.openSession(); session.beginTransaction();
Order order = new Order(); order.setPrice("998");
session.save(order);
session.getTransaction().commit(); session.close(); } |
客户关联订单,只保存客户
@Test public void demo03(){ // 3 创建客户和订单,客户关联订单,保存客户? Session session = factory.openSession(); session.beginTransaction();
//1 客户和订单 Customer customer = new Customer(); customer.setCname("成成");
Order order = new Order(); order.setPrice("998");
//2 客户关联订单 customer.getOrderSet().add(order);
//3 保存客户 session.save(customer);
session.getTransaction().commit(); session.close(); }
|
二、多对多关系映射
实体类
//Student实体类 public class Student { private Integer sid; private String sname; //用set集合来保存选的多个课程 private Set<Course> courseSet = new HashSet<Course>();
set、get..... } |
//Course实体类 public class Course { private int cid; private String cname; private Set<Student> studentSet = new HashSet<Student>(); ... } |
配置文件
Student.hbm.xml
<class name="domain.Student" table="student"> <id name="sid" column="sid"> <!-- 主键生成策略 --> <generator class="increment"></generator> </id> <!-- 一些常规属性 --> <property name="sname"></property>
<!-- 关键的地方就在这里了。一定要搞清楚两个column分别指的是什么意思 脑袋中要有哪个数据库关系图-->
<!--要查询到所有的course,就需要通过连接表,所以申明连接表的名称--> <set name="courseSet" table="student_course"> <!-- 本实体类在连接表中的外键名称,过程我们上面分析的很清楚了,为什么需要这个呢?让hibernate知道连接表中有一个外键名为s_id的指向本实体类 --> <key column="s_id"></key> <!-- 多对多映射关系,映射类和其映射类在连接表中的外键名称 这个的意思跟上面的一样,也是声明让hibernate知道,这样一来,hibernate就知道如何查询了--> <many-to-many class="domain.Course" column="c_id"></many-to-many> </set> </class> |
Course.hbm.xml
<class name="domain.Course" table="course"> <id name="cid" column="cid"> <!-- 主键生成策略 --> <generator class="increment"></generator> </id> <!-- 一些常规属性 --> <property name="cname"></property> <set name="studentSet" table="student_course"> <!-- 本类在连接表中外键的名称, --> <key column="c_id"></key> <!--多对多映射关系,映射类和其映射类在连接表中的外键名称--> <many-to-many class="domain.Student" column="s_id"></many-to-many> </set> </class> |
测试类
@Test public void demo01(){ // 1 创建客户,并保存客户--成功 Session session = factory.openSession(); session.beginTransaction();
Course course = new Course(); course.setCname("化学");
Student student = new Student(); student.setSname("qqq");
course.getStudentSet().add(student); //student.getCourseSet().add(course);
session.save(course); session.save(student);
session.getTransaction().commit(); session.close(); } |
三、一对一关系映射
实体类
//Person实体类 public class Person { private int id; private String name; private IdCard idCard;//体现一对一的关系。保存映射类的实例对象。 //。。。 } |
//Course实体类 public class IdCard { private int id; private String cardNo; private Person person;//多了这个 //... } |
配置文件
Person.hbm.xml
<class name="domain1.Person" table="person"> <id name="id" column="id"> <!-- 重点在这里。主键生成策略 因为主键跟外键是同一个,所以直接在这里申明该主键就是外键,并且指向了idCard这个类 --> <generator class="foreign"> <param name="property">idCard</param> </generator> </id> <!-- 一些常规属性 --> <property name="name"></property> <!--由于在申明主键的时候已经将关系写清楚了,所以在这里没有column这个属性。按平常的习惯,我们会在这里写上column="数据库中外键字段属性名称。"--> <!--constrained属性:就是表明我们的主键当外键使用了。 这个属性两个作用,一是通知这种对应关系在上面已经写过了,所以这里才不需要写column,二是表明这种关系是什么,也就是主键当外键。 其实还有一个级联关系的作用,这里不做多说明,具体会在这章之后一起讲解,不然会让人感觉很混乱。--> <one-to-one name="idCard" constrained="true"></one-to-one>
</class> |
IdCard.hbm.xml
<class name="domain1.IdCard" table="idcard"> <id name="id" column="id"> <!-- 主键生成策略 --> <generator class="native"> </generator> </id> <!-- 一些常规属性 --> <property name="cardNo"></property> <!-- 这里只需要写这些就足够了,因为one-to-one默认使用的就是用主键跟关联类的主键进行比较,本来就是主键关系,通过主键跟主键比较,就能达到目的,所以这个中没有column这个属性,
但是可以配置一些别的属性,不需要写column, --> <one-to-one name="person"></one-to-one> </class> |