11. 一对多关联映射

本文详细介绍了在Hibernate框架中实现一对多关联映射的方法,包括单向与双向关联的具体配置及其实现过程中的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一对多关联映射_单向

一对多关联映射利用了多对一关联映射原理

       *多对一关联映射:

                     在多的一端加入一个外键指向一的一端,它维护的关系是多指向一

       *一对多关联映射:

                     在多的一端加入一个外键指向一的一端,它维护的关系是一指向多

 

也就是说一对多和多对一的映射策略是一样的,只是站的角度不同

实例背景:

one-to-many单向关联映射

1. 定义Student

package com.bjsxt.hibernate;

 

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;

       }

}

2. 定义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.bjsxt.hibernate.Student" table="t_student">

              <id name="id">

                     <generator class="native"/>

              </id>

              <property name="name"/>

       </class>

</hibernate-mapping>

3. 定义Classes

package com.bjsxt.hibernate;

 

import java.util.Set;

 

public class Classes {

      

       private int id;  

       private String name;      

       private Set students; //尽量使用Set接口

      

       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;

       }    

}

4. 定义Classes.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 package="com.bjsxt.hibernate">

       <class name="Classes" table="t_classes">

              <id name="id">

                     <generator class="native"/>

              </id>

              <property name="name"/>

              <set name="students">

                     <key column="classesid"/>

                     <one-to-many class="Student"/>

              </set>

       </class>

</hibernate-mapping>

5. 定义Hibernate.cfg.xml文件

<!DOCTYPE hibernate-configuration PUBLIC

       "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

       "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

       <session-factory>

              <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_one2many_1</property>

              <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

              <property name="hibernate.connection.username">root</property>

              <property name="hibernate.connection.password">bjsxt</property>

              <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

              <property name="hibernate.show_sql">true</property>

             

              <mapping resource="com/bjsxt/hibernate/Classes.hbm.xml"/>

              <mapping resource="com/bjsxt/hibernate/Student.hbm.xml"/>

       </session-factory>

</hibernate-configuration>

6. 定义ExportDB类和HibernateUtils工具类()

7. 编写测试用例

package com.bjsxt.hibernate;

 

import java.util.HashSet;

import java.util.Iterator;

import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Session;

 

public class One2ManyTest extends TestCase {

 

       public void testSave1() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

                     Student student1 = new Student();

                     student1.setName("10");

                     //session.save(student1);

                    

                     Student student2 = new Student();

                     student2.setName("祖儿");

                     //session.save(student2);

                    

                     Set students = new HashSet();

                     students.add(student1);

                     students.add(student2);

                    

                     Classes classes = new Classes();

                     classes.setName("尚学堂");

                     classes.setStudents(students);

                    

                     //不能成功保存,抛出TransientObjectException异常

                            //因为studentTransient状态

                     session.save(classes);

                    

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }    

      

       public void testSave2() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

                     Student student1 = new Student();

                     student1.setName("10");

                     session.save(student1);

                    

                     Student student2 = new Student();

                     student2.setName("祖儿");

                     session.save(student2);

                    

                     Set students = new HashSet();

                     students.add(student1);

                     students.add(student2);

                    

                     Classes classes = new Classes();

                     classes.setName("尚学堂");

                     classes.setStudents(students);

                    

                            //可以正确保存

                            //Hibernate: insert into t_student(name)values(?)

                            //Hibernate: insert into t_student(name)values(?)

                            //Hibernate: insert into t_classes(name)values(?)

                            //Hibernate: update t_student set classesid = ? where id = ?

                            //Hibernate: update t_student set classesid = ? where id = ?

                            //缺点:

                            //如果将t_student表里的classesid字段设置为非空,则无法保存

                            //因为不是在student这一端维护关系,所以student不知道是哪个班的,

                          //所以需要发出多余的update语句来更新关系

                     session.save(classes);

                    

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }

 

       public void testLoad1() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

                     //正常加载

                     Classes classes = (Classes)session.load(Classes.class, 1);

                     System.out.println("classes.name=" + classes.getName());

                     Set students = classes.getStudents();

                     for (Iterator iter=students.iterator(); iter.hasNext();) {

                            Student student = (Student)iter.next();

                            System.out.println("student.name=" + student.getName());

                     }

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }           

}

一对多关联映射_双向

一对多双向关联映射:

       * 在一一端的集合上使用<key>,在对方表中加入一个外键指向一一端

       * 在多一端采用<many-to-one>

      

注意:<key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段的错误

      

如果在”一“一端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在多的一端来维护关联关系

实例背景:

 

 one-to-many双向关联映射

1. 定义Student

package com.bjsxt.hibernate;

 

public class Student {

      

       private int id;

       private String name;

       private Classes 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 Classes getClasses() {

              return classes;

       }

       public void setClasses(Classes classes) {

              this.classes = classes;

       }

}

2. 定义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.bjsxt.hibernate.Student" table="t_student">

              <id name="id">

                     <generator class="native"/>

              </id>

              <property name="name"/>

                   <!--key标签指定的外键字段必须和many-to-one指定的外键字段一致,否则引用字段的错误-->

              <many-to-one name="classes" column="classesid"/>

       </class>

</hibernate-mapping>

3. 定义Classes

package com.bjsxt.hibernate;

 

import java.util.Set;

 

public class Classes {

      

       private int id;  

       private String name;      

       private Set students; //尽量使用Set接口

      

       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;

       }    

}

4. 定义Classes.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 package="com.bjsxt.hibernate">

       <class name="Classes" table="t_classes">

              <id name="id">

                     <generator class="native"/>

              </id>

              <property name="name"/>

              <set name="students">

                     <key column="classesid"/>

                     <one-to-many class="Student"/>

              </set>

       </class>

</hibernate-mapping>

5. 定义Hibernate.cfg.xml文件

<!DOCTYPE hibernate-configuration PUBLIC

       "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

       "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

       <session-factory>

              <property name="hibernate.connection.url">jdbc:mysql://localhost/hibernate_one2many_1</property>

              <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

              <property name="hibernate.connection.username">root</property>

              <property name="hibernate.connection.password">bjsxt</property>

              <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

              <property name="hibernate.show_sql">true</property>

             

              <mapping resource="com/bjsxt/hibernate/Classes.hbm.xml"/>

              <mapping resource="com/bjsxt/hibernate/Student.hbm.xml"/>

       </session-factory>

</hibernate-configuration>

6. 定义ExportDB类和HibernateUtils工具类()

7. 编写测试用例

package com.bjsxt.hibernate;

 

import java.util.HashSet;

import java.util.Iterator;

import java.util.Set;

import junit.framework.TestCase;

import org.hibernate.Session;

 

public class One2ManyTest extends TestCase {

      

       /**

       *站在一的一端的角度来save(同单向一对多)

       */

       public void testSave1() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

                     Student student1 = new Student();

                     student1.setName("10");

                     session.save(student1);

                    

                     Student student2 = new Student();

                     student2.setName("祖儿");

                     session.save(student2);

                    

                     Set students = new HashSet();

                     students.add(student1);

                     students.add(student2);

                    

                     Classes classes = new Classes();

                     classes.setName("尚学堂");

                     classes.setStudents(students);

                    

                     //可以正确保存,但是会多发出两条sql语句

                            //同一对多关联映射_单向

                            //Hibernate: insert into t_student(name)values(?)

                            //Hibernate: insert into t_student(name)values(?)

                            //Hibernate: insert into t_classes(name)values(?)

                            //Hibernate: update t_student set classesid = ? where id = ?

                            //Hibernate: update t_student set classesid = ? where id = ?

                     session.save(classes);

                    

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }    

       /**

       *站在多的一端的角度来save(同many-to-one

       */

 

       public void testSave2() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

                     Classes classes = new Classes();

                     classes.setName("尚学堂");

                     session.save(classes);

                    

                     Student student1 = new Student();

                     student1.setName("10");

                     student1.setClasses(classes);

                     session.save(student1);

                    

                     Student student2 = new Student();

                     student2.setName("祖儿");

                     student2.setClasses(classes);

                     session.save(student2);

                    

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }           

       /**

       *站在one-to-many单向的角度load

       */

       public void testLoad1() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

                     Classes classes = (Classes)session.load(Classes.class, 1);

                     System.out.println("classes.name=" + classes.getName());

                     Set students = classes.getStudents();

                     for (Iterator iter=students.iterator(); iter.hasNext();) {

                            Student student = (Student)iter.next();

                            System.out.println("student.name=" + student.getName());

                     }

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }           

       /**

       *站在many-to-one的角度load

       */

       public void testLoad2() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

                    

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

                     System.out.println("student.name=" + student.getName());

                     System.out.println("student.classes.name=" + student.getClasses().getName());

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }                  

}

上述一对多关联映射_双向,如果从一对多的角度来处理,仍然存在多发出两条update语句,并且外键关联字段(classesid)不能设置为null的问题,可以采用inverse+cascade属性的方式来解决这个问题。

关于inverse属性:

       inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,

默认inversefalse 如果设置成inversetrue,当我们从一一端来维护关联关系时, Hibernate会自动转向多一端来维护。      

       注意:inverse属性,只影响数据的存储,也就是持久化         

inversecascade

       * inverse是关联关系的控制方向

       * cascade操作上的连锁反应

注:inverse必须和cascade配合使用才能达到反转的效果。

1. 修改Classes.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 package="com.bjsxt.hibernate">

       <class name="Classes" table="t_classes">

              <id name="id">

                     <generator class="native"/>

              </id>

              <property name="name"/>

              <set name="students" inverse="true" cascade="all">

                     <key column="classesid"/>

                     <one-to-many class="Student"/>

              </set>

       </class>

</hibernate-mapping>

2. 编写测试用例

       //在一对多双向关联映射中站在一的一端来处理save操作

       public void testSave() {

              Session session = null;

              try {

                     session = HibernateUtils.getSession();

                     session.beginTransaction();

 

                     Classes classes = new Classes();

                     classes.setName("尚学堂");

                    

                     Student student1 = new Student();

                     student1.setName("10");

                     //因为hibernateinvert到多的一端,即处理方式类似于many-to-one

                            //所以需要student1.setClasses(classes);

                            //因为设置了cascade属性,所以不要写session.save(student1),否则仍然会多发update语句

                     student1.setClasses(classes);

                     //session.save(student1);仍然会多发update语句

                    

                     Student student2 = new Student();

                     student2.setName("祖儿");

                     student2.setClasses(classes);

                    

                     Set students = new HashSet();

                     students.add(student1);

                     students.add(student2);

                    

                     classes.setStudents(students);

                    

                            //可以正确保存,同many-to-onesave方式

                            //Hibernate: insert into t_classes (name) values (?)

                            //Hibernate: insert into t_student(name,classesid) values (?,?)

                            //Hibernate: insert into t_student(name,classesid) values (?,?)

                     session.save(classes);

                    

                     session.getTransaction().commit();

              }catch(Exception e) {

                     e.printStackTrace();

                     session.getTransaction().rollback();

              }finally {

                     HibernateUtils.closeSession(session);

              }

       }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值