Hibernate中的一对多

本文详细介绍了在ORM框架中如何实现一对多关系的设置、解除及删除操作,并深入解析了inverse属性的作用。

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

1. 一对多

      1)设置一对多关系
           即不管从多的一方还是一的一方都能找到另一方
           1-1  一的一方的pojo:
     public class Department {
        private Integer id;
        private String name;
        private Set<Employee> employees = new HashSet<Employee>();
        ........
    }

           1-2  多的一方的pojo:

     public class Employee {
        private Integer id;
        private String name;
        private Department department;
        .....
     } 
        
            1-3 一的一方的映射文件
  <class name="cn.com.cpf.pojo.Department"   table="t_department" >
         <id name="id" column="id">
            <generator class="native"/>
         </id>
         <property name="name"/>
         <set name="employees" table="t_employees">
            <key column="departmentId"/>
            <one-to-many class="cn.com.cpf.pojo.Employee"/>
        </set>
    </class>



          理解:1>和集合的映射基本相同,只是其中的元素是Class,所以不再使用element,而是使用on-to-many
                      2>key 还是另一张表的外键
                      3>因为在一对多映射中,原来的集合表就是现在的多的一方的表(多的一方存储一方的主键,用来关联),所以table就不用指明了,这里是为了便于理解,所以才加上表名

           1-4  多的一方的映射文件
    <class name="cn.com.cpf.pojo.Employee" table="t_employee">
          <id name="id" column="id">
            <generator class="native"/>
          </id>
          <property name="name" length="20"/>
          <many-to-one name="department" class="cn.com.cpf.pojo.Department" column="departmentId"></many-to-one>
   </class>

           因为要表明是多对一的关系,所以使用many-to-one标签,column用来存储外键,其他的和一般属性完全相同。

          1-5  测试
 
         Employee xny = new Employee();
         xny.setName("xny");
         Employee zq = new Employee();
         zq.setName("zq");

         Set<Employee> employees = new HashSet<Employee>();
         employees.add(zq);
         employees.add(xny);

         Department department = new Department();
         department.setName("cpf");
         department.setEmployees(employees);

         zq.setDepartment(department);
         xny.setDepartment(department);

         session.save(zq);
         session.save(xny);
         session.save(department);

                 结果为:
         Hibernate: insert into t_employee (name, departmentId) values (?, ?)
         Hibernate: insert into t_employee (name, departmentId) values (?, ?)
         Hibernate: insert into t_department (name) values (?)
         Hibernate: update t_employee set name=?, departmentId=? where id=?
         Hibernate: update t_employee set name=?, departmentId=? where id=?
         Hibernate: update t_employee set departmentId=? where id=?
         Hibernate: update t_employee set departmentId=? where id=?

               说明:
              1>  因为Employee插入在Department之前,这时候Department还没有id(因为此处使用自增长),所以只能先设置null,等Department插入了,有了id,再update,设置外键departmentId,这就有了前两条update。
              2>  因为Department一方还没有设置关联,所以就有了后两条update,是Department声明一对多关系
              3>  所谓的谁维护关系,就是谁来设置这个外键的值
              
              由上可以推出:
             1>  既然先插入Employee要等待Department的id,所以先插入Department再插入Employee可以节省两条update
           session.save(department);
           session.save(zq);
           session.save(xny);
                  结果为:
Hibernate: insert into t_department (name) values (?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: insert into t_employee (name, departmentId) values (?, ?)
Hibernate: update t_department set departmentId=? where id=? Hibernate: update t_department set departmentId=? where id=?

             2>   既然在employee一端已经在插入的时候设置了外键值,那么没有必要再让department一端再设置了,通过inverse属性可以告诉department不用再设置了
            
        <set name="employees" table="t_employees" inverse="true">
            <key column="departmentId"/>
            <one-to-many class="cn.com.cpf.pojo.Employee"/>
        </set>
           session.save(department);
           session.save(zq);
           session.save(xny);
                结果为:
           Hibernate: insert into t_department (name) values (?)
           Hibernate: insert into t_employee (name, departmentId) values (?, ?)
           Hibernate: insert into t_employee (name, departmentId) values (?, ?)

            理解:inverse意思为反转,也就是告诉Hibernate,映射关系你不用管了。(类比Spring的Ioc,inversion of control,控制反转,也就是生成实例这件事你不用管了,交给Spring,自己来取就行了)

         2)解除一对多关系
              实际上也就是将外键设置为null(因为所谓的对应关系也就是一个外键而已)
            1> 从多的一方解除
         Employee em = (Employee) session.get(Employee.class, 1);
         em.setDepartment(null);
               结果:
       Hibernate: update t_employee set name=?, departmentId=? where id=?
           2> 从一的一方解除
            前提:必须inverse属性设置为false,不然他都不管理了怎么可能解除关系?
          Department department = (Department) session.get(Department.class, 2);
          Employee o = (Employee) session.get(Employee.class, 3);
          department.getEmployees().remove(o);

          3) 删除关联对象
              1>  删除多的一方
          Employee em = (Employee) session.get(Employee.class, 1);
          session.delete(em);
              结果:直接删,对一的一方完全无影响(因为外键就保存在自己这里,删了也就连关系一起删了,肯定无影响)
              2> 删除一的一方
                  a.和多的对象没有关联——直接删,当然无影响
                  b.和多的对象有关联,inverse属性为true
                     inverse为true,不能管理外键,所以删除就会报异常
         Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails 
                 c.和多的对象有关联,inverse属性为false
                    可以删,因为自己可以管理外键
              结果:
       Hibernate: update t_employee set departmentId=null where departmentId=?
       Hibernate: delete from t_department where id=?
               可以看到先设置外键为null,再删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值