Hibernate之关联关系

时间:2017-1-20 16:28

——一对多配置

1、第一步:创建实体类
    *   客户实体
    *   订单实体

示例代码:
        /**

* 客户实体

* @author WYC

*

*/

public class Customer {

private Integer cid;

private String name;

// 一个客户有多个订单
            // 拥有哪些订单

private Set<Order> orders = new HashSet<Order>();
            set() / get()...

}

/**

* 订单实体

* @author WYC

*

*/

public class Order {

private Integer oid;

private String addr;

// 订单属于某一个客户

private Customer customer;

set() / get()...
        }

2、第二步:建立映射

1)Customer的映射

<hibernate-mapping>

<class name="com.wyc.hibernate3.demo2.Customer" table="customer">

<id name="cid" column="cid">

<generator class="native"/>

</id>

<property name="cname" column="cname" length="20"/>

<!-- 配置映射 -->

<!-- 因为属性是一个集合,所以需要配置集合 -->

<!-- name:Customer对象中关联对象的属性名称 -->

<set name="orders">

<!-- key标签中的column用来描述一对多关系中多的一方的外键的名称 -->

<key column="cid"></key>

<!-- 配置一个<one-to-many>,用来指定多的一方的实体类 -->

<one-to-many class="com.wyc.hibernate3.demo2.Order"/>

</set>

</class>

</hibernate-mapping>

2)Order的映射

<hibernate-mapping>

<class name="com.wyc.hibernate3.demo2.Order" table="order_table">

<id name="oid" column="oid">

<generator class="native"/>

</id>

<property name="addr" column="addr" length="50"/>

<!-- 配置映射 -->

<!-- <many-to-one>标签

name:关联对象的属性名称

column:外键的名称

class:关联对象类的全路径

-->

<many-to-one name="customer" column="cid" class="com.wyc.hibernate3.demo2.Customer" />

</class>

</hibernate-mapping>

one-to-many和many-to-one中的column必须一致,否则会创建两个外键。

3、第三步:将映射放到核心配置文件中

——一对多级联保存

级联:操作当前对象的时候,关联的对象如何处理?

1、通常情况下如果想要向数据库插入数据,需要每个对象都要save一次,例如:

public class HibernateDemo2 {

@Test

// 向客户表插入一个客户,在订单表中插入两个订单

public void fun1() {

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 定义一个客户

*/

Customer customer = new Customer();

customer.setCname("张三");

/*

* 定义两个订单

*/

Order order1 = new Order();

order1.setAddr("奎文区");

Order order2 = new Order();

order2.setAddr("高新区");

/*

* 建立关系

*/

order1.setCustomer(customer);

order2.setCustomer(customer);

customer.getOrders().add(order1);

customer.getOrders().add(order2);

session.save(customer);

session.save(order1);

session.save(order2);

tx.commit();

session.close();

}

}

2、能否只保存其中一个?从而完成保存两条数据
    可以使用级联保存。

级联保存的方向性:
        *   保存客户时选择级联订单(在Customer中配置级联)
        *   保存订单的时候选择级联客户。(在Order中配置级联)

不能直接save()其中一个持久态对象,否则会抛出异常:org.hibernate.TransientObjectException

3、级联保存示例代码

/*

* 保存订单,同时级联客户

* 当保存订单时,需要关联Customer对象,所以需要在many-to-one上进行配置一个属性:

*  cascade="save-update",表示在保存或更新时会级联操作

*/

public void fun4(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 定义一个客户

*/

Customer customer = new Customer();

customer.setCname("张三");

/*

* 定义一个订单

*/

Order order1 = new Order();

order1.setAddr("奎文区");

/*

* 建立关系

*/

order1.setCustomer(customer);

customer.getOrders().add(order1);

/*

* 只保存一方

*/

session.save(order1);

tx.commit();

session.close();

}

/*

* 保存客户,同时级联订单

* 当保存客户时,需要关联Set集合,所以需要在Set集合上进行配置一个属性:

*  cascade="save-update",表示在保存或更新时会级联操作

*/

public void fun3(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 定义一个客户

*/

Customer customer = new Customer();

customer.setCname("张三");

/*

* 定义一个订单

*/

Order order1 = new Order();

order1.setAddr("奎文区");

/*

* 建立关系

*/

order1.setCustomer(customer);

customer.getOrders().add(order1);

/*

* 只保存一方

*/

session.save(customer);

tx.commit();

session.close();

}

——一对多级联删除

1、不配置级联删除的情况下:
    示例代码:

/*

* 如果不配置级联删除,会将外键置为null,然后再删除记录

*/

public void fun5(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 删除客户

* 如果想要级联删除,则必须先查询再删除

*/

Customer customer = (Customer) session.get(Customer.class, 1);

session.delete(customer);

tx.commit();

session.close();

}

2、配置级联删除的情况下,删除客户的时候级联删除订单:

需要在Customer.hbm.xml的<set>标签上配置cascade="delete",如果cascade有多个值,可以用逗号隔开。

示例代码:

/*

* 级联删除

*/

public void fun6(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 级联删除:先查询,再删除

*/

/*

* 删除客户时级联删除订单

* 在<set>标签中配置cascade="delete"

*/

Customer customer = (Customer) session.get(Customer.class, 1);

session.delete(customer);

/*

* 删除订单时级联删除客户

* 需要在Order.hbm.xml中的many-to-one中配置cascade="delete"

*/

Order order = (Order) session.get(Order.class, 1);

session.delete(order);

tx.commit();

session.close();

}

——cascade取值

1、none
    不使用级联,是默认值。

2、save-update
    保存或更新时级联。

3、delete
    删除时级联。

4、all
    除了孤儿删除以外所有的操作都会级联。

5、delete-orphan
    孤儿删除(孤子删除)
    仅限于一对多,因为只有一对多的时候才有主从(父子)关系存在。
    一的一方是主(父)方。
    多的一方是从(子)方。

当一个客户与某个订单解除了关系时,相当于把订单的外键置为null,订单就没有了所属客户了,那么就会将这种记录删除。

删除没有外键的记录。

6、all-delete-orphan
    包含了孤儿删除的所有级联操作。

7、孤儿删除示例代码:

/*

* 孤儿删除

* 在Customer.hbm.xml中<set>标签上配置cascade="delete-orphan"

*/

public void fun7(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 让2号客户与2号订单解除关系

*/

Customer customer = (Customer) session.get(Customer.class, 2);

Order order = (Order) session.get(Order.class, 2);

// 将该客户对应的其中某一订单删除后,该订单的外键就是null了

customer.getOrders().remove(order);

tx.commit();

session.close();

}

——双向维护 - 产生多余SQL

配置inverse="true",在哪一端配置,配置的那一端就放弃了外键的维护权。

示例代码:

/*

* 双向维护:自动更新数据库,会产生多余的SQL

* 双方都有维护外键的能力,要想不产生多余SQL,必须让其中一方放弃外间的维护权:<set inverse="true">

* 一般情况下都是“多”的一方维护外键关系

*/

public void fun8(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

/*

* 将3号客户的订单改为1号客户的订单

*/

Customer customer = (Customer) session.get(Customer.class, 1);

Order order = (Order) session.get(Order.class, 3);

/*

* 持久态对象如果发生变化会自动更新数据库

* 会发送两条update语句

*/

customer.getOrders().add(order);

order.setCustomer(customer);

tx.commit();

session.close();

}

——cascade和inverse的区别

cascade:操作关联对象
inverse:控制外键的维护

示例代码:

/*

* 区分cascade和inverse

*

* 在Customer.hbm.xml中配置:<set name="orders" cascade="save-update" inverse="true" >

*/

public void fun9(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

Customer customer = new Customer();

customer.setCname("张三");

Order order = new Order();

order.setAddr("奎文");

// 客户关联订单

customer.getOrders().add(order);

/*

* 客户是否保存到数据库:保存

* 订单是否保存到数据库:保存,因为设置了cascade="save-update",但是订单的外键是null

* 因为在Customer中设置了inverse="true",说明外键不属于Customer来维护
         * 只有在插入订单时,才会产生外键

*/

session.save(customer);

tx.commit();

session.close();

}

——多对多的配置

1、学生实体类

public class Student {

private Integer sid;

private String sname;

private Set<Course> courses = new HashSet<Course>();

@Override

public String toString() {

return "Student [sid=" + sid + ", sname=" + sname + ", courses=" + courses + "]";

}

public Set<Course> getCourses() {

return courses;

}

public void setCourses(Set<Course> courses) {

this.courses = courses;

}

public Integer getSid() {

return sid;

}

public void setSid(Integer sid) {

this.sid = sid;

}

public String getSname() {

return sname;

}

public void setSname(String sname) {

this.sname = sname;

}

}

2、课程实体类

public class Course {

private Integer cid;

private String cname;

private Set<Student> students = new HashSet<Student>();

public Integer getCid() {

return cid;

}

public void setCid(Integer cid) {

this.cid = cid;

}

public String getCname() {

return cname;

}

public void setCname(String cname) {

this.cname = cname;

}

public Set<Student> getStudents() {

return students;

}

public void setStudents(Set<Student> students) {

this.students = students;

}

}

3、Student.hbm.xml
    <?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>

<class name="com.wyc.hibernate3.demo3.Student" table="student">

<id name="sid" column="sid">

<generator class="native"></generator>

</id>

<property name="sname" column="sname" length="20" />

<!-- 配置关联映射 -->

<!-- 多对多时存在中间表,table属性写中间表的名称,两个类中的table必须一致,否则生成多个中间表 -->

<set name="courses" table="stu_cour">

<!-- key标签中的column写本类在中间表中的外键字段 -->

<key column="sid" />

<!-- many-to-many中的class是另一方类的全路径,column表示另一方类在中间表中外键的名称 -->

<many-to-many class="com.wyc.hibernate3.demo3.Course" column="cid"></many-to-many>

</set>

</class>

</hibernate-mapping>

4、Course.hbm.xml
    <?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>

<class name="com.wyc.hibernate3.demo3.Course" table="course">

<id name="cid" column="cid">

<generator class="native"></generator>

</id>

<property name="cname" column="cname" length="20" />

<!-- 配置与学生关联的映射 -->

<set name="students" table="stu_cour" inverse="true" >

<key column="cid" />

<many-to-many class="com.wyc.hibernate3.demo3.Student" column="sid"/>

</set>

</class>

</hibernate-mapping>

5、将映射配置文件添加到核心配置文件中

——多对多的保存操作

如果在多对多的情况下进行保存,则必须有一方放弃主键维护,不然会导致主键重复。

通常是主动方来维护主键,比如学生选课,学生来维护主键。

需要在Course.hbm.xml中添加<set inverse="true">来指定Course放弃维护主键。

public class HibernateDemo3 {

@Test

/*

* 保存学生和课程 为学生选择一些课程

*/

public void fun1() {

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

// 创建学生

Student student1 = new Student();

student1.setSname("张三");

Student student2 = new Student();

student2.setSname("李四");

// 创建课程

Course course1 = new Course();

course1.setCname("Java");

Course course2 = new Course();

course2.setCname("Android");

// 张三选择1号课程和2号课程

student1.getCourses().add(course1);

student1.getCourses().add(course2);

course1.getStudents().add(student1);

course2.getStudents().add(student1);

// 李四选1号课程

student2.getCourses().add(course1);

course1.getStudents().add(student2);

// 执行保存

session.save(student1);

session.save(student2);

session.save(course1);

session.save(course2);

tx.commit();

session.close();

}

}

——多对多级联保存

/*

* 级联操作:保存学生,关联课程

* 在Student.hbm.xml中配置cascade="save-update"

*/

public void fun2() {

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

// 创建学生

Student student = new Student();

student.setSname("王五");

// 创建课程

Course course = new Course();

course.setCname("PHP");

student.getCourses().add(course);

course.getStudents().add(student);

session.save(student);

tx.commit();

session.close();

}

——删除中间表信息

获取中间表后将记录从集合中删除即可。

/*

* 删除1号学生的选课信息

*/

public void fun3() {

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

// 查询1号学生

Student student = (Student) session.get(Student.class, 1);

// 查询1号课程

Course course = (Course) session.get(Course.class, 1);

// 删除选课信息

student.getCourses().remove(course);

tx.commit();

session.close();

}

——总结

1、一对一的配置
    *   在多的一方:<many-to-one>
    *   在一的一方:<set> <key /> <one-to-many> </set>
2、多对多的配置
    *   <set> <key /> <many-to-many /> </set>
    在多对多关系的情况下,需要有一方放弃外键维护权。
3、级联操作
    *    save-update
    *   delete
    *   all
    *   delete-orphan(孤儿删除)
    *   all-delete-orphan
4、inverse
    放弃外键维护权
    通常在一的一方放弃。

时间: 2024-10-19 10:29:58

Hibernate之关联关系的相关文章

Rhythmk 学习 Hibernate 08 - Hibernate annotation 关联关系注解

1.一对一 (One to One)    共三种情况:     1.1 主键共享    1.2 外键共享 1.3 中间表关联 1.1  code: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Entity public class article {     @Id     @GeneratedValue    public Integer getArticleId() {         return articleId;     }     .....  

Hibernate三 关联关系之单向关联

一 分类Hibernate的关联关系可分为:单向关联和双向关联单向关联包括:1->1 1->N N->1 N->N 双向关联包括:1->1 1->N N->N二 单向N->1关联1.程序应该在N的一端的持久化类中增加一个属性,该属性引用1的一端的关联实体对于N->1关联,都需要在N的一端使用@ManyToOne修饰代表关联实体的属性,该注解可以指定以下属性:(1)cascade:指定Hibernate对关联实体采用怎样的级联策略,包括以下五种情况:Ca

Hibernate之关联关系映射(一对一主键映射和一对一外键映射)

1:Hibernate的关联关系映射的一对一外键映射: 1.1:第一首先引包,省略 1.2:第二创建实体类: 这里使用用户信息和身份证信息的关系,用户的主键编号既可以做身份证信息的主键又可以做身份证信息的外键,这里先做外键. 创建User.java: 用户和身份证一对一的关联关系映射       private IdCart idCart; IdCart.java: 身份证和用户,一对一的关系       private User user; 1 package com.bie.bean; 2

Hibernate利用关联关系操纵对象

利用关联关系操纵对象 数据对象之间关联关系有一对一.一对多及多对多关联关系.在数据库操作中,数据对象之间的关联关系使用JDBC处理很困难.本节讲解如何在Hibernate中处理这些对象之间的关联关系.本节使用到4个类,它们分别是Student(学生).Card(学生证).Group(班级)和Course(课程),它们之间的关联关系如图1-1所示.这些实体存在级联(cascade)问题.例如,当删除一个班级的信息时,还要删除该班的所有学生的基本信息.如果直接使用JDBC执行这种级联操作,会非常烦琐

Hibernate的关联关系映射

系统设计的实体间关系分别为:一对一,一对多(多对一),多对多 一.一对多(多对一) 一对多,多对一其实一样,只是站在不同的角度看,这种情况在多的一方添加一的一方的主键为外键.以学生Student和班级Grade为例介绍一对多关联关系在hibernate映射文件中的配置. Student.hbm.xml映射文件配置(多的一方有外键) <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hib

Hibernate 一对一关联关系

在Hibernate中,一对一关联关系有两种情况: 基于外键映射的一对一 基于主键映射的一对一 基于外键映射的一对一 这种映射其实是由多对一而来,这种映射情况下,外键可以放在任意的一端,在需要存放外键的一端(简称a端),添加<many-to-one>节点,为<many-to-one>节点增加unique="true"属性来约束多对一成为一对一,另一端(简称b端)使用<one-to-one>节点来映射,并增加property-ref属性指定使用在该端(

Hibernate四 关联关系之双向关联

双向关联 一 双向1--N关联 1.无连接表的双向1--N关联 N的一端需要使用@ManyToOne注解来修饰代表关联实体的属性,1的一端需要使用@OneToMany注解来修饰代表关联实体的属性. 双向关联应该由N的一端来控制关联关系,因此在使用@OneToMany注解时指定mappedBy属性.一旦为@OneToMany,@ManyToMany指定了该属性,则表明当前实体不能控制关联关系,一旦当前实体放弃控制关联关系后,hibernate就不允许使用@JoinColumn或@JoinTable

Hibernate 实体关联关系映射(转载)

原文链接地址:http://lavasoft.blog.51cto.com/62575/39398/ Hibernate:Hibernate关联关系映射实例速查 Hibernate关联关系映射目录│ ├─单向关联│  ├─  一对一外键单向关联│  ├─  一对一主键单向关联│  ├─  一对一连接表单向关联│  ├─  一对多外键单向关联│  ├─  一对多连接表单向关联│  ├─  多对一外键单向关联│  ├─  多对一连接表单向关联│  └─  多对多单向关联└─双向关联    ├─  一

Hibernate一对一关联关系

一对一的关联关系有一下几类: 1. 单向一对一 a). 基于主键的 b). 基于外键的 2. 双向一对一 a). 基于外键的 好, 下面咱们主要说一下怎么来设置这种关系, 主要是说怎么用, 其中也说一下一些地方为什么这么配置. OneByOne 一: 基于主键的 单向一对一 我们使用 Person类和 IdCard类来做测试, 一个Person 只能对应一个 IdCard. Just So. Person类: package com.single.one2one_primary; public

Hibernate 实体关联关系映射【转】

Hibernate关联关系映射目录│ ├─单向关联│  ├─  一对一外键单向关联│  ├─  一对一主键单向关联│  ├─  一对一连接表单向关联│  ├─  一对多外键单向关联│  ├─  一对多连接表单向关联│  ├─  多对一外键单向关联│  ├─  多对一连接表单向关联│  └─  多对多单向关联└─双向关联    ├─  一对一外键双向关联    ├─  一对一主键双向关联    ├─  一对一连接表双向关联    ├─  一对多外键双向关联    ├─  一对多连接表双向关联