`
mzhj
  • 浏览: 227622 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

14、JPA中的多对多双向关联的各项关系操作

阅读更多

目录结构,看图:



 
Student.java

package cn.itcast.bean;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class Student {
	private Integer id;
	private String name;
	private Set<Teacher> teachers = new HashSet<Teacher>();

	public Student() {
	}

	public Student(String name) {
		this.name = name;
	}

	@Id
	@GeneratedValue
	// id作为实体标识符,并且采用数据库的id自增长方式生成主键值。
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(length = 10, nullable = false)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@ManyToMany(cascade = CascadeType.REFRESH)
	@JoinTable(name = "student_teacher", inverseJoinColumns = @JoinColumn(name = "teacher_id"), joinColumns = @JoinColumn(name = "student_id"))
	public Set<Teacher> getTeachers() {
		return teachers;
	}

	/*
	  假如不对关联表里的字段做任何设定,那么表里面的字段默认由JPA的实现产品来帮我们自动生成。
	  inverseJoinColumns:inverse中文是反转的意思,但是觉得太恶心了,在JPA里,可以理解为被维护端。
	  inverseJoinColumns:被维护端外键的定义。
	  @JoinColumn:外键名称(中间表跟teacher表的主键关联的那个外键名称)。
	  joinColumns:关系维护端的定义。
	 */

	public void setTeachers(Set<Teacher> teachers) {
		this.teachers = teachers;
	}

	public void addTeacher(Teacher teacher) {
		this.teachers.add(teacher);
	}

	public void removeTeacher(Teacher teacher) {
		if(this.teachers.contains(teacher)){  //凭什么判断teacher在集合teachers中呢?是根据teacher的id。这就要求必要重写Teacher.java的hasCode和equals方法,通过这两个方法来判断对象是否相等。
			this.teachers.remove(teacher);
		}
	}
}

 


Teacher.java

package cn.itcast.bean;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Teacher {
	private Integer id;
	private String name;
	private Set<Student> students = new HashSet<Student>();

	public Teacher() {
	}

	public Teacher(String name) {
		this.name = name;
	}

	@Id
	@GeneratedValue
	// id作为实体标识符,并且采用数据库的id自增长方式生成主键值。
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(length = 10, nullable = false)
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@ManyToMany(cascade = CascadeType.REFRESH, mappedBy = "teachers")
	public Set<Student> getStudents() {
		return students;
	}

	/*
	  cascade: CascadeType.PERSIST:级联保存不要,学生没来之前,老师就已经在了。
	  CascadeType.MERGE:级联更新不要,把学生的信息改了,没必要修改相应的老师的信息,压根就没这业务需求。
	  CascadeType.REMOVE:级联删除更不要,如果双方都设了级联删除,加入删除学生,会删除相应的老师,被删除的老师又跟学生发生千丝万缕的关系,又把一批学生删掉.....没完没了...最终的结果可能是数据里面所有的记录都被清掉。
	  所以在多对多关系中,级联删除通常是用不上的 这里只需设置级联涮新CascadeType.PERSIST就可以了,事实上refresh方法也很少使用。
	  mappedBy: 通过这个属性来说明老师是关系被维护端 fetch: 加载行为默认是延迟加载(懒加载),凭Many。 这里不需要设置。
	 */

	public void setStudents(Set<Student> students) {
		this.students = students;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		//判断的依据是,如果id不为null的话,就返回id的哈希码。
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Teacher other = (Teacher) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}
}

 

 


ManyToManyTest.java

package junit.test;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.junit.BeforeClass;
import org.junit.Test;

import cn.itcast.bean.Student;
import cn.itcast.bean.Teacher;

public class ManyToManyTest {

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@Test
	public void save() {
		EntityManagerFactory factory = Persistence
				.createEntityManagerFactory("itcast");
		EntityManager em = factory.createEntityManager();
		em.getTransaction().begin();

		em.persist(new Student("小张同学"));
		em.persist(new Teacher("李勇老师"));

		em.getTransaction().commit();
		em.close();
		factory.close();
	}

	/*
	 * 建立学生跟老师的关系
	 */
	@Test
	public void buildTS() {
		EntityManagerFactory factory = Persistence
				.createEntityManagerFactory("itcast");
		EntityManager em = factory.createEntityManager();
		em.getTransaction().begin();

		Student student = em.find(Student.class, 1);	// 首先要得到学生,因为学生是关系维护端,通过关系维护端来建立关系。
		student.addTeacher(em.getReference(Teacher.class, 1));	//这方法在业务意义上,就代表建立跟老师的关系。
		//所谓建立跟老师的关系,无非就是把老师加进集合里面去。
		//建立关系,体现在JDBC上面,就是添加一条记录进中间表。

		em.getTransaction().commit();
		em.close();
		factory.close();
	}

	/*
	 * 解除学生跟老师的关系
	 */
	@Test
	public void deleteTS() {
		EntityManagerFactory factory = Persistence
		.createEntityManagerFactory("itcast");
		EntityManager em = factory.createEntityManager();
		em.getTransaction().begin();

		Student student = em.find(Student.class, 1);	// 首先要得到学生,因为学生是关系维护端,通过关系维护端来建立关系。
		student.removeTeacher(em.getReference(Teacher.class, 1));	//这方法在业务意义上,就代表解除跟老师的关系。
		//所谓解除跟老师的关系,无非就是把老师从集合里面删去。
		//解除关系,体现在JDBC上面,就是在中间表删除一条记录。

		em.getTransaction().commit();
		em.close();
		factory.close();
	}

	/*
	 * 删除老师,老师已经跟学生建立起了关系(错误写法)
	 */
	@Test
	public void deleteTeacher1() {
		EntityManagerFactory factory = Persistence
		.createEntityManagerFactory("itcast");
		EntityManager em = factory.createEntityManager();
		em.getTransaction().begin();


		em.remove(em.getReference(Teacher.class, 1));
		//并不需要发生数据装载行为,只需要一个托管状态的实体,所以用getReference可以提供性能。

		em.getTransaction().commit();
		em.close();
		factory.close();
	}
	/*
	 该方法会出错,因为中间表中已经有记录了,会抛出以下错误:
	Caused by: java.sql.BatchUpdateException:
		Cannot delete or update a parent row: a foreign key constraint fails
		(`itcast/student_teacher`, CONSTRAINT `FKD4E389DE1D49449D` FOREIGN KEY (`teacher_id`)
		REFERENCES `teacher` (`id`))
	关系被维护端没有权力更新外键,所以不会删除中间表的记录。
	 */

	/*
	 * 删除老师,老师已经跟学生建立起了关系(正确写法)
	 */
	@Test
	public void deleteTeacher2() {
		EntityManagerFactory factory = Persistence
		.createEntityManagerFactory("itcast");
		EntityManager em = factory.createEntityManager();
		em.getTransaction().begin();

		Student student = em.find(Student.class, 1);
		Teacher teacher = em.getReference(Teacher.class, 1);
		//并不需要发生数据装载行为,只需要一个托管状态的实体,所以用getReference可以提供性能。
		student.removeTeacher(teacher);
		//student是关系维护端,有权利删除外键,只要在对象中删除了teacher,那么中间表中相关外键记录也就被删除了。
		//想要删除teacher记录,必须先通过student解除关系才行。
		em.remove(teacher);

		em.getTransaction().commit();
		em.close();
		factory.close();
	}

	/*
	 * 删除学生,老师已经跟学生建立起了关系
	 */
	@Test
	public void deleteStudent() {
		EntityManagerFactory factory = Persistence
		.createEntityManagerFactory("itcast");
		EntityManager em = factory.createEntityManager();
		em.getTransaction().begin();

		Student student = em.getReference(Student.class, 1);
		em.remove(student);	//这样是可以删除学生的,尽管目前是有关系,中间表有关联记录,有外键约束。但是我们现在要删除的是关系维护端,关系维护端是有权力对外键进行增删改查操作的。删除的时候,Hibernate会判断student是关系维护端,然后去中间表把关联记录先删除掉。再删掉student对象。

		em.getTransaction().commit();
		em.close();
		factory.close();
	}
}

 

  • 大小: 17.8 KB
分享到:
评论

相关推荐

    14_传智播客JPA详解_JPA中的多对多双向关联的各项关系操作

    通过本教程,你可以学习到如何在JPA中设置和操作多对多双向关联,理解其背后的数据库操作,并掌握处理关联的技巧,从而更好地利用JPA进行数据持久化。在实际开发中,灵活运用这些知识能帮助你构建出更加高效和易于...

    JPA中的一对多双向关联与级联操作

    这篇博客将深入探讨JPA中的一对多双向关联以及级联操作。 首先,让我们理解一对多关联。假设我们有两个实体,一个是`User`(用户)和一个是`Post`(帖子)。一个用户可以发布多个帖子,但一个帖子只能属于一个用户...

    JPA中的多对多双向关联实体定义与注解设置

    在Java Persistence API (JPA) 中,多对多(ManyToMany)关系是表示两个实体之间复杂关联的一种方式。这种关联允许一个实体实例可以与多个其他实体实例相关联,反之亦然。例如,一个学生可以选修多门课程,一门课程...

    14_JPA详解_JPA中的多对多双向关联的各项关系操作.zip

    在本教程中,我们将深入探讨JPA中的多对多双向关联及其各项操作。 ### 1. 多对多关联基础 在关系型数据库中,多对多关联通常通过中间表来实现,而JPA提供了一种声明式的方式来处理这种关联。在双向关联中,两个...

    13_jpa多对多双向关联实体定义与注解

    在Java世界中,Java Persistence API(JPA)是Oracle公司推出的用于...通过"13_传智播客JPA详解_JPA中的多对多双向关联实体定义与注解设置"的学习,开发者可以更好地应用这些概念,提升代码质量和数据库操作的灵活性。

    JPA详解视频教程 第14讲 JPA中的多对多双向关联的各项关系操作.avi

    JPA用于整合现有的ORM技术,可以简化现有Java EE和Java SE应用对象持久化的开发工作,实现ORM的统一。JPA详解视频教程 第14讲 JPA中的多对多双向关联的各项关系操作.avi

    JPA中的一对一双向关联

    在Java Persistence API (JPA) 中,一对一双向关联是一种关系映射,它允许两个实体类之间存在一对一的关系,并且每个实体都能引用对方。这种关联是双向的,意味着每个实体都可以通过自己的属性访问到另一个实体。...

    13_JPA详解_JPA中的多对多双向关联实体定义与注解设置.zip

    本资料“13_JPA详解_JPA中的多对多双向关联实体定义与注解设置”专注于讲解JPA如何处理多对多双向关联关系,这是数据库设计中常见的一种复杂关联类型。下面我们将详细探讨这一主题。 首先,我们需要理解多对多关联...

    10_JPA详解_JPA中的一对多双向关联与级联操作.zip

    本资料包"10_JPA详解_JPA中的一对多双向关联与级联操作.zip"聚焦于JPA中的一个重要概念——一对多双向关联及其级联操作。以下是对这一主题的详细阐述。 **一对多关联** 在关系数据库设计中,一对多关联是最常见的...

    JPA_2_一对多双向关联关系

    在`Employee`实体中,`@ManyToOne`注解表示多对一的关系,`@JoinColumn`注解指定了外键所在的列名。 为了使双向关联正常工作,还需要在每个实体的setter方法中添加一些额外的逻辑,以确保两边的关系同步: ```java...

    10_传智播客JPA详解_JPA中的一对多双向关联与级联操作

    本教程将深入探讨JPA中的一对多双向关联及级联操作,这对于理解和使用JPA进行复杂数据模型管理至关重要。 首先,我们来理解一下一对多关联。在数据库设计中,一对多关联是指一个实体(表)可以与多个其他实体相关联...

    12_传智播客JPA详解_JPA中的一对一双向关联

    在JPA中实现一对一双向关联需要在两个实体类中分别定义关系。 首先,我们来看如何在实体类中定义一对一的关联。假设我们有`Employee`和`Department`两个实体,它们之间是一对一的关系。在`Employee`实体中,我们...

    12_JPA详解_JPA中的一对一双向关联.zip

    在Java世界中,Java Persistence API(JPA)是用于管理和持久化对象的规范,它使得开发者可以方便地在...在实际项目中,结合其他关联类型,如一对多、多对一、多对多,可以构建出更加灵活、符合业务逻辑的数据模型。

    JPA详解视频教程 第10讲 JPA中的一对多双向关联与级联操作.avi

    JPA用于整合现有的ORM技术,可以简化现有Java EE和Java SE应用对象持久化的开发工作,实现ORM的统一。JPA详解视频教程 第10讲 JPA中的一对多双向关联与级联操作.avi

    JPA详解视频教程 第13讲 JPA中的多对多双向关联实体定义与注解设置.avi

    JPA用于整合现有的ORM技术,可以简化现有Java EE和Java SE应用对象持久化的开发工作,实现ORM的统一。JPA详解视频教程 第13讲 JPA中的多对多双向关联实体定义与注解设置.avi

    JPA中实现双向多对多的关联关系示例代码

    本文将深入探讨在JPA中如何实现双向多对多的关联关系,并提供相关的示例代码。 首先,我们需要了解多对多关联关系的基本概念。在关系型数据库中,两个实体之间可能存在多对多的关系,意味着每个实例可以从一个实体...

    JPA详解视频教程 第12讲 JPA中的一对一双向关联.avi

    JPA用于整合现有的ORM技术,可以简化现有Java EE和Java SE应用对象持久化的开发工作,实现ORM的统一。JPA详解视频教程 第12讲 JPA中的一对一双向关联.avi

    JPA学习总结(二)--JPAOneToOne双向关联

    本文主要探讨的是JPA中的`@OneToOne`注解,它用于建立两个实体之间的一对一关联关系。在实际开发中,这种关联关系常常出现在需要精确映射一对一实体映射的情况,例如用户与个人信息、车辆与车牌号等。我们将会深入...

    JPA-4 映射关联关系

    JPA 提供了多种方式来处理不同类型的关联关系,包括单向多对一、单向一对多、双向一对一、双向多对一和双向多对多。下面我们将详细探讨这些关联关系的实现方法。 1. **单向多对一关联关系(SingleManyToOne)** 在...

Global site tag (gtag.js) - Google Analytics