hibernate之关于关联映射的综合应用

【hibernate】之关于关联映射的综合应用


1、关联映射如何处理业务逻辑

2、如何指定中间表

3、如何进行级联操作

4、如何解决Hibenrate建表过程中主键错乱问题

现在有三张表

Student(学生表),Course(课程表),Score(学生,课程,分数,表)

那么我们分析业务逻辑可知,学生和课程是多对多的关系,学生和分数表是一对多的关系,课程和分数也是一对多的关系。

直接看Annotations配置,在这里我所有的配置都是双向关联,这样在分数,课程,学生,之中,可以任意找到彼此!

@Entity
@Table(name="c_course")
public class Course {
	private Integer id;
	private String coursename;
	private Set<Student> students=new HashSet<Student>();
	private Set<Score> scores=new HashSet<Score>();

	@OneToMany(mappedBy="course")//必须指定关系由多的一方维护
	public Set<Score> getScores() {
		return scores;
	}
	public void setScores(Set<Score> scores) {
		this.scores = scores;
	}
	@ManyToMany//指定中间表是s_score
	@JoinTable(name="s_score",joinColumns={@JoinColumn(name="course_id")},
			inverseJoinColumns={@JoinColumn(name="student_id")})
	public Set<Student> getStudents() {
		return students;
	}
	public void setStudents(Set<Student> students) {
		this.students = students;
	}
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@Column(name="c_coursename")
	public String getCoursename() {
		return coursename;
	}
	public void setCoursename(String coursename) {
		this.coursename = coursename;
	}
}

(课程表Course)

@Entity
@Table(name="t_student")
public class Student {
	private Integer id;
	private String name;
	private Set<Course> courses=new HashSet<Course>();
	private Set<Score> scores=new HashSet<Score>();

	@OneToMany(mappedBy="student")
	public Set<Score> getScores() {
		return scores;
	}
	public void setScores(Set<Score> scores) {
		this.scores = scores;
	}
	@ManyToMany
	@JoinTable(name="s_score",joinColumns={@JoinColumn(name="student_id")},
			inverseJoinColumns={@JoinColumn(name="course_id")})
	public Set<Course> getCourses() {
		return courses;
	}
	public void setCourses(Set<Course> courses) {
		this.courses = courses;
	}
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@Column(name="s_name")
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

}

(Student学生表)

@Entity
@Table(name="s_score")
public class Score {
	private Integer id;
	private String score;
	private Student student;
	private Course course;

	@ManyToOne(cascade={CascadeType.ALL})//配置级联操作
	@JoinColumn(name="student_id")
	public Student getStudent() {
		return student;
	}
	public void setStudent(Student student) {
		this.student = student;
	}
	@ManyToOne(cascade={CascadeType.ALL})
	@JoinColumn(name="course_id")
	public Course getCourse() {
		return course;
	}
	public void setCourse(Course course) {
		this.course = course;
	}
	@Id
	@GeneratedValue
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@Column(name="s_score")
	public String getScore() {
		return score;
	}
	public void setScore(String score) {
		this.score = score;
	}

}

(分数表,也是中间关联表,Score)

那么问题来了,采用Hibernate自动建表,我们看一下建表语句

12:11:08,169 DEBUG SchemaExport:415 - 
    create table c_course (
        id integer not null auto_increment,
        c_coursename varchar(255),
        primary key (id)
    )
12:11:08,333 DEBUG SchemaExport:415 - 
    create table s_score (
        id integer not null,
        s_score varchar(255),
        course_id integer,
        student_id integer not null auto_increment,
        primary key (student_id, course_id)
    )
12:11:08,455 DEBUG SchemaExport:415 - 
    create table t_student (
        id integer not null auto_increment,
        s_name varchar(255),
        primary key (id)
    )

我们发现在建表是Hibernate默认将student_id和course_id联合作为主键使用,且student_id还是自增

这样显然是不对的,在这里我也实在想不到,好的办法,智能采用一个笨的办法,手动改回来!

大家最好是采用工具操作,因为,你直接create的话,student_id和course_id关联不上student,course的主键ID

ok,到这里,我们的建表基本完成,下面JunitTest

	@Test
	public void add(){
		try {
			Configuration cfg=new Configuration();
			cfg.configure();
			SessionFactory	sessionFactory=cfg.buildSessionFactory();
			Session session=sessionFactory.openSession();
			session.beginTransaction();
			Student student1=new Student();
			student1.setName("张三1");
//			Student student2=new Student();
//			student2.setName("李四");
			Course c1=new Course();
			c1.setCoursename("数学1");
			Course c2=new Course();
			c2.setCoursename("语文1");
//			session.save(student1);
//			session.save(c1);
//			session.save(student2);
//			session.save(c2);
			Score score=new Score();
			score.setScore("901");
			score.setCourse(c1);
			score.setStudent(student1);
			//张三数学90分
			session.save(score);
			Score score2=new Score();
			score2.setCourse(c2);
			score2.setScore("100");
			score2.setStudent(student1);
			session.save(score2);
			session.getTransaction().commit();
			session.close();
			sessionFactory.close();
		} catch (HibernateException e) {
			e.printStackTrace();
		}
	}

ok,大家可以看出,为什么我们最后只需要保存score就行呢?没有session.save()student和course,为什么也能直接保存数据库中?这就是

cascade={CascadeType.ALL}

级联操作,当然我这里配置的是ALL,其实还有4个参数,大家可以自己慢慢研究!

以上添加成功,那么我们直接load试一下

public void findTest(){
		Configuration cfg=new Configuration();
		cfg.configure();
		SessionFactory	sessionFactory=cfg.buildSessionFactory();
		Session s=sessionFactory.openSession();
		s.beginTransaction();
		Student student=(Student)s.load(Student.class, 2);
		System.out.println("学生姓名"+student.getName());
		for(Course course:student.getCourses()){
			System.out.print("--------"+"课程名称"+course.getCoursename());
			for(Score score:course.getScores()){
				System.out.println("--------"+"课程分数"+score.getScore());
			}
		}
		s.getTransaction().commit();
		s.close();
		sessionFactory.close();
	}

也没问题

update呢?

public void	update(){
		Configuration cfg=new Configuration();
		cfg.configure();
		SessionFactory	sessionFactory=cfg.buildSessionFactory();
		Session s=sessionFactory.openSession();
		s.beginTransaction();
		Student student=(Student)s.load(Student.class,1);
		//我们现在把查询出来语文成绩改为0分
		for(Course course:student.getCourses()){
			System.out.println(course.getCoursename());
			if("语文".equals(course.getCoursename())){
				for(Score score:course.getScores()){
					if(score.getStudent().getId().equals(student.getId())){
						score.setScore("0");
						s.update(score);
					}
				}
			}
		} 
		s.getTransaction().commit();
		s.close();
		sessionFactory.close();
	}


删除?


@Test
	public void deleteObj(){
		Configuration cfg=new Configuration();
		cfg.configure();
		SessionFactory	sessionFactory=cfg.buildSessionFactory();
		Session s=sessionFactory.openSession();
		s.beginTransaction();
		Student student=(Student)s.load(Student.class,3);
		s.delete(student);
		s.getTransaction().commit();
		s.close();
		sessionFactory.close();

	}

ok,到这里基本上,完成Hibernate关联映射的基本操作!


注意,多对多删除的时候,我们一般删除的是中间表数据?但是往往由于外键关联的关系,Hibernate会删除另一张表中的数据来解除关联关系,这就不对了!后续再探讨!




时间: 2024-10-12 14:39:16

hibernate之关于关联映射的综合应用的相关文章

Hibernate之1-N关联映射

一.Hibernate之1-N关联映射 1. 哪边是 1 , 哪边是多 ? 需要从业务的角度来说明.例如,Employee 和 Department 之间就是 n-1 的关联关系,Order 和 Customer 之间也是 n-1 的关联关系. 1). 关联关系是有方向的: 2). 如何在类中来建立关联关系呢 ? 解:通过成员变量的方式即可. 2. 单向 n-1 关联关系 1). 域对象中,在 Order 中声明一个 Customer 类型的成员变量,并提供 setter.getter publ

hibernate多对一关联映射

hibernate多对一关联映射: 实体类 (POJO) public class Student{ private int stuId; private String stuNum; private String stuName; private ClassRoom cr; } public class ClassRoom{ private int claId; private String claName; } 映射文件 <class name=" Student" tabl

Hibernate一对一双向关联映射

关键原因在于对象模型具有方向性: 单向:一端只能加载另一端,不能反过来. 双向:两端都可以加载另一端. 问题来了:如何我们想从身份证端(IdCard)加载人(Person),怎么办呢? 下面我们开始介绍一对一的双向关联映射. 映射原理 双向关联映射与单向关联映射的原理是一样的,双向关联映射并不影响存储,只影响加载.所以,双向关联映射和单向关联映射的关系模型是一样的即数据库的表结构是一样的,只是IdCard的实体类和配置文件(IdCard.hbm.xml)发生了一点点变化. 对象模型 从上图中可以

【Hibernate步步为营】--关联映射之多对一

上篇文章讨论了Hibernate的基本映射,一个实体类对应着一张表,在相应的Hibernate Mapping文件中使用<class>标签映射.并且实体类中的普通属性对应着表字段,使用<property>标签映射.另外在构造实体类时应注意:在实体类中应实现无参的默认的构造函数,提供一个标示,建议不要使用final修饰实体类,为实体类生成getter和setter方法,最后介绍了几种主要的主键生成策略,接下来讨论多对一映射. 一.关联映射之多对一 对于多对一关联映射其实很容易理解,在

【Hibernate】——一对一关联映射

两个对象之间如果是一对一的关系,如Person-IdCard.在Hibernate中有两种策略可以实现一对一的关联映射: 主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系:数据库表不会有额外的字段来维护它们之间的关系,仅通过表得主键来关联. 唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关联关系: 而每种策略又分为两种方向的对应关系,即单向一对一关系和双向一对一关系.分类的原因一般是由需求决定的,单双向是站在不同的角度去看人

hibernate的数据关联映射

数据关联映射分为:一对多.多对一,一对一,多对多. cascade属性• save-update:在执行保存和修改是进行级联操作• delete:在执行删除时进行级联操作• all:在所有情况下进行级联操作• none:不进行级联操作(默认) 抓取策略 一对多.多对一 一对多.多对一持久化类设计 // User类 public class User { private int id; private String name; private int age; private Set<Addres

Hibernate框架之关联映射入门

关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用. 一:配置单向多对一关联 在Emp类中定义一个Dept属性,而在Dept类中无须定义用于存放Emp对象的集合属性 01.Dept.java package cn.zhang.entity; //部门实体类 public class Dept { private Integer deptid;//编号 private String deptname;//名称 public Integer getDeptid() { return

Hibernate一对多关联映射的配置及其级联删除问题

首先举一个简单的一对多双向关联的配置: 一的一端:QuestionType类 package com.exam.entity; import java.util.Set; public class QuestionType { private String typeName; private char typeUniqueness; private Set quesion; public String getTypeName() { return typeName; } public void

Hibernate第二章关联映射的总结

1.type值的解释:如下图: 1)type的值,不是java语言的一个类型的全称,而是一个hibernate自定义 的类型的名称. 2)Type的值,其实是对应hibernate中的一个类型的简称,而由 org.hibernate.type包下面的类型来真正完成java类型与数据库类型的传 换. 2.单类对单表的映射配置 1)类型的处理: I.各种:type II.精度:precision,scale III.逻辑值的处理:boolean,yes_no 2)主键的处理 Native,assig