【Hibernate3】(5)关联映射(二)

来源:互联网 发布:odysseusota4 windows 编辑:程序博客网 时间:2024/05/22 04:26

一. 一对多双向关联

在Contact类中,新建关于Group的成员:
public class Contact {private int id;private String name;private Group group;public Group getGroup() {return group;}public void setGroup(Group group) {this.group = group;}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;}@Overridepublic String toString() {return "Contact [id=" + id + ", name=" + name + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + id;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Contact other = (Contact) obj;if (id != other.id)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}
配置文件中重新配置:
<class name="Contact" table="t_contact" lazy="true"><id name="id"><generator class="increment" /></id><property name="name" /><many-to-one name="group" cascade="all" column="groupId"lazy="false"></many-to-one></class>
注意,一端和多段两个配置文件的column值一定要一样。
看下面这3个测试方法:
/** * 一对多双向关联一端维护数据 *  */public void testOne2Many() {Group g = new Group();g.setName("朋友");Contact c = new Contact();c.setName("张一");Contact c2 = new Contact();c2.setName("张二");Contact c3 = new Contact();c3.setName("张三");g.addContact(c);g.addContact(c2);g.addContact(c3);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(g);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}/** * 一对多双向关联多端维护数据 *  */public void testOne2Many2() {Group g = new Group();g.setName("朋友");Contact c = new Contact();c.setName("张一");Contact c2 = new Contact();c2.setName("张二");Contact c3 = new Contact();c3.setName("张三");c.setGroup(g);c2.setGroup(g);c3.setGroup(g);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(c);session.save(c2);session.save(c3);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}/** * 一对多双向关联两端端维护数据 *  */public void testOne2Many3() {Group g = new Group();g.setName("朋友");Contact c = new Contact();c.setName("张一");Contact c2 = new Contact();c2.setName("张二");Contact c3 = new Contact();c3.setName("张三");c.setGroup(g);c2.setGroup(g);c3.setGroup(g);g.addContact(c);g.addContact(c2);g.addContact(c3);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(c);session.save(c2);session.save(c3);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
前两个方法是从一端或者多端维护数据的,执行后会发现只执行了这4条语句:
Hibernate: insert into t_group (name, id) values (?, ?)Hibernate: insert into t_contact (name, groupId, id) values (?, ?, ?)Hibernate: insert into t_contact (name, groupId, id) values (?, ?, ?)Hibernate: insert into t_contact (name, groupId, id) values (?, ?, ?)
但是第三个方法执行后会发现:
Hibernate: insert into t_group (name, id) values (?, ?)Hibernate: insert into t_contact (name, groupId, id) values (?, ?, ?)Hibernate: insert into t_contact (name, groupId, id) values (?, ?, ?)Hibernate: insert into t_contact (name, groupId, id) values (?, ?, ?)Hibernate: update t_contact set groupId=? where id=?Hibernate: update t_contact set groupId=? where id=?Hibernate: update t_contact set groupId=? where id=?
执行了4条插入语句后,又执行了3条更新的语句,那么怎么可以变的不这么冗余呢?
我们在一的这一段配置这样一个属性inverse
<set name="contacts" cascade="all" lazy="extra" inverse="true"><key column="groupId" /><one-to-many class="Contact" /></set>
就可以了,执行后发现又变回了4条插入语句。

2. 关联重建

public void testOne2Many4() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Group g = (Group) session.get(Group.class, 2);System.out.println(g.getName() + "当中元素有:");for (Contact c : g.getContacts()) {System.out.println(c.getName() + ", 所属 "+ c.getGroup().getName() + "组");}trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
使用这个可以使得OGNL表达式更加简单。

3. 自关联

假设我们有这样子的一个员工类:
public class Employee {private int id;private String name;private Employee manager;private Set<Employee> puisne = new HashSet<Employee>();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 Employee getManager() {return manager;}public void setManager(Employee manager) {this.manager = manager;}public Set<Employee> getPuisne() {return puisne;}public void setPuisne(Set<Employee> puisne) {this.puisne = puisne;}}
每一个员工可以有自己的主管,也可以有底下的属下,它们同样都是Employee泪,那么配置文件可以这样子配置:
<class name="Employee" table="t_employee"><id name="id"><generator class="increment" /></id><property name="name" /><many-to-one name="manager" cascade="all" column="managerId" /><set name="puisne" cascade="all" inverse="true" lazy="extra"managerId " /><one-to-many class="Employee" /></set></class>
测试添加数据:
public void testOne2Many5() {Employee root = new Employee();root.setName("国王");Employee manager = new Employee();manager.setName("张总");Employee manager2 = new Employee();manager2.setName("王总");root.getPuisne().add(manager);root.getPuisne().add(manager2);manager.setManager(root);manager2.setManager(root);Employee e = new Employee();e.setName("张一");Employee e2 = new Employee();e2.setName("张二");Employee e3 = new Employee();e3.setName("王五");e.setManager(manager);e2.setManager(manager);e3.setManager(manager);e.setManager(manager);e2.setManager(manager);e3.setManager(manager2);manager.getPuisne().add(e);manager.getPuisne().add(e2);manager2.getPuisne().add(e3);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(root);trans.commit();} catch (HibernateException ex) {trans.rollback();ex.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
利用递归的方法取出所有数据:
/** * 一对多双向关联关联取数据 *  */public void testOne2Many6() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Employee root = (Employee) session.get(Employee.class, 1);out(root, 0);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}private void out(Employee emp, int level) {if (emp != null) {for( int i = 0; i < level; i++) {System.out.print("---");}System.out.println(level + "级" + emp.getName());if (emp.getPuisne() != null && emp.getPuisne().size() > 0) {for (Employee e : emp.getPuisne()) {out(e, level + 1);}}}}

二. 一对一关联

1. 共享主键关联

看这两个类:
public class User {private int id;private String username;private String password;private Employee emp;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Employee getEmp() {return emp;}public void setEmp(Employee emp) {this.emp = emp;}}
public class Employee {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;}}
配置文件:
<class name="User" table="t_user"><id name="id"><generator class="foreign"><param name="property">emp</param></generator></id><property name="username" /><property name="password" /><one-to-one name="emp" constrained="true" /></class>
<class name="Employee" table="t_employee"><id name="id"><generator class="increment" /></id><property name="name" /></class>
由于要实现一对一共享主键,所以在User的配置文件中id的generator不能再是increment了,要配置成外键foreign,参数写上下面one-to-one的name,即emp。

(1). 单向关联

public void test() {User user = new User();user.setUsername("张三");user.setPassword("11");Employee emp = new Employee();emp.setName("张三");user.setEmp(emp);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(user);session.save(emp);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
要想实现双向关联,修改Employee类,添加user以及user的get和set方法。
配置文件只需加入:
<one-to-one name="user"></one-to-one>

(2). 双向关联

public void test2() {User user = new User();user.setUsername("张三");user.setPassword("11");Employee emp = new Employee();emp.setName("张三");user.setEmp(emp);emp.setUser(user);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(user);session.save(emp);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

(3). 重建

public void test3() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Employee emp = (Employee) session.get(Employee.class, 0);System.out.println(emp.getName());System.out.println(emp.getUser().getUsername());System.out.println(emp.getUser().getEmp().getUser().getEmp().getUser().getUsername());trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

2. 唯一外键关联

(1). 单向关联

只需修改配置文件即可:
<class name="User" table="t_user"><id name="id"><generator class="increment"/></id><property name="username" /><property name="password" /><many-to-one name="emp" column="empId" unique="true"/></class>
<class name="Employee" table="t_employee"><id name="id"><generator class="increment" /></id><property name="name" /></class>

(2). 双向关联

<class name="User" table="t_user"><id name="id"><generator class="increment"/></id><property name="username" /><property name="password" /><many-to-one name="emp" column="empId" unique="true" cascade="all"/></class>
<class name="Employee" table="t_employee"><id name="id"><generator class="increment" /></id><property name="name" /><one-to-one name="user"  property-ref="emp" cascade="all"/></class>

三. 多对多关联

1. 单向关联

创建Student类和Teacher类,他们都有id和name成员,还有彼此的set集合成员,注意要复写hashCode方法和equals方法,配置方法如下:
<class name="Teacher" table="t_teacher"><id name="id"><generator class="increment"/></id><property name="name" /></class>
<class name="Student" table="t_student"><id name="id"><generator class="increment"/></id><property name="name" /><set name="teachers" table="t_student_teacher"><key column="studentId"/><many-to-many class="Teacher" column="teacherId"/></set></class>
测试:
public void test() {Teacher t = new Teacher();t.setName("张老师");Teacher t2 = new Teacher();t2.setName("王老师");Student s = new Student();s.setName("张学生");Student s2 = new Student();s2.setName("王学生");s.getTeachers().add(t);s.getTeachers().add(t2);s2.getTeachers().add(t);s2.getTeachers().add(t2);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(t);session.save(t2);session.save(s);session.save(s2);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

2. 双向关联

修改Teacher配置文件:
<class name="Teacher" table="t_teacher"><id name="id"><generator class="increment" /></id><property name="name" /><set name="students" table="t_student_teacher"><key column="teacherId" /><many-to-many class="Student" column="studentId" /></set></class>
测试:
public void test2() {Teacher t = new Teacher();t.setName("张老师");Teacher t2 = new Teacher();t2.setName("王老师");Student s = new Student();s.setName("张学生");Student s2 = new Student();s2.setName("王学生");s.getTeachers().add(t);s.getTeachers().add(t2);s2.getTeachers().add(t);s2.getTeachers().add(t2);t.getStudents().add(s);t.getStudents().add(s2);t2.getStudents().add(s);t2.getStudents().add(s2);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(t);session.save(t2);session.save(s);session.save(s2);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}
执行会发现报错,和前面一样,两个表都视图维护数据,这样子做是不行的,必须放弃一端,我们在Teacher配置文件中修改:
<set name="students" table="t_student_teacher" cascade="all" inverse="true"><key column="teacherId" /><many-to-many class="Student" column="studentId" /></set>

3. 重建

public void test2() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Teacher t = (Teacher) session.get(Teacher.class, 1);System.out.println(t.getName() + "的学生:");for (Student s : t.getStudents()) {System.out.println(s.getName() + "的老师:");for (Teacher teacher : s.getTeachers()) {System.out.println(teacher.getName() + ",");}}trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

四. 一对多替代多对多关联

1. 一对多关联

创建新的StudentTeacher类:
public class StudentTeacher {private int id;private Student student;private Teacher teacher;private Date startTime;public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}public Date getStartTime() {return startTime;}public void setStartTime(Date startTime) {this.startTime = startTime;}public int getId() {return id;}public void setId(int id) {this.id = id;}}
修改之前的类,使用studentTeacher做成员变量:
public class Student {private int id;private String name;private Set<StudentTeacher> studentTeachers = new HashSet<StudentTeacher>();
public class Teacher {private int id;private String name;private Set<StudentTeacher> studentTeachers = new HashSet<StudentTeacher>();
修改配置文件:
<class name="Student" table="t_student"><id name="id"><generator class="increment"/></id><property name="name" /><set name="studentTeachers" cascade="all" inverse="true"><key column="studentId"/><one-to-many class="StudentTeacher" /></set></class>
<class name="Teacher" table="t_teacher"><id name="id"><generator class="increment" /></id><property name="name" /><set name="studentTeachers" cascade="all" inverse="true"><key column="teacherId" /><one-to-many class="StudentTeacher" /></set></class>
创建StudentTeacher.hbm.xml:
<class name="StudentTeacher" table="t_student_teacher"><id name="id"><generator class="increment" /></id><property name="startTime" /><many-to-one name="student" column="studentId" cascade="all" /><many-to-one name="teacher" column="teacherId" cascade="all" /></class>
测试:
public void test() {Teacher t = new Teacher();t.setName("张老师");Teacher t2 = new Teacher();t2.setName("王老师");Student s = new Student();s.setName("张学生");Student s2 = new Student();s2.setName("王学生");StudentTeacher st = new StudentTeacher();st.setTeacher(t);st.setStudent(s);StudentTeacher st2 = new StudentTeacher();st2.setTeacher(t);st2.setStudent(s2);StudentTeacher st3 = new StudentTeacher();st3.setTeacher(t2);st3.setStudent(s);StudentTeacher st4 = new StudentTeacher();st4.setTeacher(t2);st4.setStudent(s2);t.getStudentTeachers().add(st);t.getStudentTeachers().add(st2);t2.getStudentTeachers().add(st3);t2.getStudentTeachers().add(st4);Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();session.save(t);session.save(t2);trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}

2. 重建

public void test2() {Session session = HibernateUtil.getSession();// 创建及开启事务对象Transaction trans = null;try {trans = session.beginTransaction();Teacher t = (Teacher) session.get(Teacher.class, 1);for (StudentTeacher st : t.getStudentTeachers()) {System.out.println(st.getTeacher().getName() + "的学生:"+ st.getStudent().getName());}trans.commit();} catch (HibernateException e) {trans.rollback();e.printStackTrace();} finally {HibernateUtil.closeSession(session);}}


0 0