Hibernate关联映射之一对多、多对多映射

来源:互联网 发布:火星时代 知乎 编辑:程序博客网 时间:2024/06/05 17:56

一对多关联映射

1.单向关联StuClasses--->Student

    一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端。
    它们的区别在于维护的关系不同:
 多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
 一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
    采用<set>、<one-to-many>标签

    示例:
    Student实体:
public class Student {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
    Student.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Student" table="t_stu"><id name="id"><generator class="native" /></id><property name="name" /></class></hibernate-mapping>
    StuClasses实体:
public class StuClasses {private int id;private String name;private Set students;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set getStudents() {return students;}public void setStudents(Set students) {this.students = students;}}
    StuClasses.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.StuClasses" table="t_class"><id name="id"><generator class="native" /></id><property name="name" /><set name="students"><key column="classId"></key><!-- 会在Student表中增加classId字段 --><one-to-many class="com.zero.hibernate.vo.Student" /></set></class></hibernate-mapping>
   生成的建表语句:
    alter table t_stu         drop         foreign key FK_b3ldr8gswf50qyucsr6t5aglq    drop table if exists t_class    drop table if exists t_stu    create table t_class (        id integer not null auto_increment,        name varchar(255),        primary key (id)    )    create table t_stu (        id integer not null auto_increment,        name varchar(255),        classId integer,        primary key (id)    )    alter table t_stu         add constraint FK_b3ldr8gswf50qyucsr6t5aglq         foreign key (classId)         references t_class (id)
   测试:
Student s1 = new Student();s1.setName("AAA");Student s2 = new Student();s2.setName("BBB");Set<Student> set = new HashSet<Student>();set.add(s1);set.add(s2);StuClasses stuClasses = new StuClasses();stuClasses.setName("1");stuClasses.setStudents(set);session.save(stuClasses);//抛出TransientObjectException//因为Student不是Persistent状态的对象,它是Transient状态的对象

Student s1 = new Student();s1.setName("AAA");Student s2 = new Student();s2.setName("BBB");session.save(s1);session.save(s2);Set<Student> set = new HashSet<Student>();set.add(s1);set.add(s2);StuClasses stuClasses = new StuClasses();stuClasses.setName("1");stuClasses.setStudents(set);session.save(stuClasses);//可以成功保存数据,但是会发出多余的update语句来维持关系// session.save(s1)执行时-----Hibernate: insert into t_stu (name) values (?),此时classId字段为NULL//session.save(s2)执行时-----Hibernate: insert into t_stu (name) values (?),此时classId字段为NULL//session.save(stuClasses)执行时-----Hibernate: insert into t_class (name) values (?)// transaction.commit()执行时-----Hibernate: update t_stu set classId=? where id=?;                                  Hibernate: update t_stu set classId=? where id=?
    因此存在缺陷:
         因为多的一端Student不知道StuClasses的存在(也就是Student没有维护与StuClasses的关系),所以在保存Student的时候关系字段classId是为null的,如果将该关系字段设置为非空,则将无法保存数据。
         另外因为Student不维护关系,而StuClasses维护关系,StuClasses就会发出多余的update语句,保证StuClasses和Student有关系,这样加载StuClasses的时候才可以把该Classes对应的学生加载上来。


2.双向关联StuClasses<--->Student

    采用一对多双向关联映射的目的主要是为了主要是为了解决一对多单向关联的缺陷。
    一对多双向关联的映射方式:
 * 在一的一端的集合上采用<key>、<one-to-many>标签
 * 在多的一端采用<many-to-one>标签
 注意:<key>标签和<many-to-one>标签加入的字段保持一致,否则会产生数据混乱

   示例:
   Student实体:
public class Student {private int id;private String name;private StuClasses classes;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public StuClasses getClasses() {return classes;}public void setClasses(StuClasses classes) {this.classes = classes;}}
    Student.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Student" table="t_stu"><id name="id"><generator class="native" /></id><property name="name" /><many-to-one name="classes" column="classId"/></class></hibernate-mapping>
    StuClasses实体:
public class StuClasses {private int id;private String name;private Set students;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set getStudents() {return students;}public void setStudents(Set students) {this.students = students;}}
    StuClasses.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.StuClasses" table="t_class"><id name="id"><generator class="native" /></id><property name="name" /><set name="students"><key column="classId"></key><!-- 会在Student表中增加classId字段 --><one-to-many class="com.zero.hibernate.vo.Student" /></set></class></hibernate-mapping>
    生成的建表指令:
    alter table t_stu         drop         foreign key FK_b3ldr8gswf50qyucsr6t5aglq    drop table if exists t_class    drop table if exists t_stu    create table t_class (        id integer not null auto_increment,        name varchar(255),        primary key (id)    )    create table t_stu (        id integer not null auto_increment,        name varchar(255),        classId integer,        primary key (id)    )    alter table t_stu         add constraint FK_b3ldr8gswf50qyucsr6t5aglq         foreign key (classId)         references t_class (id)
    测试:
Student s1 = new Student();s1.setName("AAA");Student s2 = new Student();s2.setName("BBB");Set<Student> set = new HashSet<Student>();set.add(s1);set.add(s2);StuClasses stuClasses = new StuClasses();stuClasses.setName("1");stuClasses.setStudents(set);session.save(stuClasses);//抛出TransientObjectException//因为Student不是Persistent状态的对象,它是Transient状态的对象

Student s1 = new Student();s1.setName("AAA");Student s2 = new Student();s2.setName("BBB");session.save(s1);session.save(s2);Set<Student> set = new HashSet<Student>();set.add(s1);set.add(s2);StuClasses stuClasses = new StuClasses();stuClasses.setName("1");stuClasses.setStudents(set);session.save(stuClasses);//可以成功保存数据,但是会发出多余的update语句来维持关系// session.save(s1)执行时----- Hibernate: insert into t_stu (name, classId) values (?, ?),此时classId字段为NULL//session.save(s2)执行时----- Hibernate: insert into t_stu (name, classId) values (?, ?),此时classId字段为NULL//session.save(stuClasses)执行时-----Hibernate: insert into t_class (name) values (?)// transaction.commit()执行时-----Hibernate: update t_stu set classId=? where id=?;                                  Hibernate: update t_stu set classId=? where id=?

StuClasses stuClasses = new StuClasses();stuClasses.setName("1");session.save(stuClasses);Student s1 = new Student();s1.setName("AAA");s1.setClasses(stuClasses);session.save(s1);Student s2 = new Student();s2.setName("BBB");s2.setClasses(stuClasses);session.save(s2);//可以成功保存数据
    <set>标签中inverse属性:inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效。
    所以一对多关联映射通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true。即采用上述测试的第二例方式保存数据,由多的一端保存。


多对多关联映射

    将生成一张表来存储关联关系

1.单向关联Student--->Course

    示例:
    Student实体:
public class Student {private int id;private String name;private Set courses;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set getCourses() {return courses;}public void setCourses(Set courses) {this.courses = courses;}}
    Student.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Student" table="t_stu"><id name="id"><generator class="native" /></id><property name="name" /><set name="courses" table="t_stu_course"><!-- 新建t_stu_course关联表 --><key column="stuId" /><many-to-many class="com.zero.hibernate.vo.Course"column="courseId" /></set></class></hibernate-mapping>
    Course实体:
public class Course {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
    Course.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Course" table="t_course"><id name="id"><generator class="native" /></id><property name="name" /></class></hibernate-mapping>
    生成的建表指令:
    alter table t_stu_course         drop         foreign key FK_dgu19n5u0jubpeaw432v2cuq1    alter table t_stu_course         drop         foreign key FK_i8gk0e57sefdsmk7cev6eqc2c    drop table if exists t_course    drop table if exists t_stu    drop table if exists t_stu_course    create table t_course (        id integer not null auto_increment,        name varchar(255),        primary key (id)    )    create table t_stu (        id integer not null auto_increment,        name varchar(255),        primary key (id)    )    create table t_stu_course (        stuId integer not null,        courseId integer not null,        primary key (stuId, courseId)    )    alter table t_stu_course         add constraint FK_dgu19n5u0jubpeaw432v2cuq1         foreign key (courseId)         references t_course (id)    alter table t_stu_course         add constraint FK_i8gk0e57sefdsmk7cev6eqc2c         foreign key (stuId)         references t_stu (id)
    测试:
Course course1 = new Course();course1.setName("数学");session.save(course1);Course course2 = new Course();course2.setName("语文");session.save(course2);Course course3 = new Course();course3.setName("英语");session.save(course3);Student student1 = new Student();student1.setName("AAA");Set stu1Course = new HashSet();stu1Course.add(course1);stu1Course.add(course2);student1.setCourses(stu1Course);session.save(student1);Student student2 = new Student();student2.setName("BBB");Set stu2Course = new HashSet();stu2Course.add(course2);stu2Course.add(course3);student2.setCourses(stu2Course);session.save(student2);

Student stu = (Student)session.load(Student.class, 2);System.out.println(stu.getName());for (Iterator iter=stu.getCourses().iterator(); iter.hasNext();) {   Course course = (Course)iter.next();   System.out.println(course.getName());}


2.双向关联Student<---> Course

    示例:
    Student实体:
public class Student {private int id;private String name;private Set courses;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set getCourses() {return courses;}public void setCourses(Set courses) {this.courses = courses;}}
    Student.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Student" table="t_stu"><id name="id"><generator class="native" /></id><property name="name" /><set name="courses" table="t_stu_course"><!-- 新建t_stu_course关联表 --><key column="stuId" /><many-to-many class="com.zero.hibernate.vo.Course"column="courseId" /></set></class></hibernate-mapping>
    Course实体:
public class Course {private int id;private String name;private Set students;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set getStudents() {return students;}public void setStudents(Set students) {this.students = students;}}
    Course.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Course" table="t_course"><id name="id"><generator class="native" /></id><property name="name" /><set name="students" table="t_stu_course"><key column="courseId" /><many-to-many class="com.zero.hibernate.vo.Student"column="stuId" /></set></class></hibernate-mapping>
    生成的建表指令:
    alter table t_stu_course         drop         foreign key FK_dgu19n5u0jubpeaw432v2cuq1    alter table t_stu_course         drop         foreign key FK_i8gk0e57sefdsmk7cev6eqc2c    drop table if exists t_course    drop table if exists t_stu    drop table if exists t_stu_course    create table t_course (        id integer not null auto_increment,        name varchar(255),        primary key (id)    )    create table t_stu (        id integer not null auto_increment,        name varchar(255),        primary key (id)    )    create table t_stu_course (        stuId integer not null,        courseId integer not null,        primary key (courseId, stuId)    )    alter table t_stu_course         add constraint FK_dgu19n5u0jubpeaw432v2cuq1         foreign key (courseId)         references t_course (id)    alter table t_stu_course         add constraint FK_i8gk0e57sefdsmk7cev6eqc2c         foreign key (stuId)         references t_stu (id)

0 0
原创粉丝点击