• 【Hibernate框架】关联映射(一对多,多对一)


    根据我们的总结计划,上篇文章我们总结了有关于一对一映射相关知识,接下来,我们进行下一个阶段,一对多、多对一映射相关知识。

    场景设定:

           国家规定,一个人只能在一个公司上班,一个公司可以拥有很多员工。我们就利用这个场景,根据针对对象的不同,我们分别来分析一下一对多、多对一关联映射。

    一、多对一单向关联映射

    1、多对一单向关联映射:对于员工(Employee)来说,他跟公司(Company)的对应关系就是多对一关系

    Po对象:Employee.Java

     

    1. public class Employee {  
    2.     public int id;  
    3.     public String name;  
    4.     public Company company;  
    5.     //getter、setter  
    6. }  
    Company.java

     

    1. public class Company{  
    2.     public int id;  
    3.     public String name;  
    4.     //getter、setter  
    5. }  
           作为程序员,我们都知道在设计数据库要在多对一的多那一面添加一的外键,所以我们在员工类中,添加对公司类的引用。

    映射文件:Employee.hbm.xml

     

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Employee" table="t_employee">  
    3.             <id name="id" type="int">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.             <many-to-one name="company" column="companyid"/>  
    8.     </class>  
    9. </hibernate-mapping>    
    Company.hbm.xml

     

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Company" table="t_company">  
    3.             <id name="id">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.     </class>  
    8. </hibernate-mapping>  
    执行程序自动生成表:

     

    1. create table t_company (id integer not null auto_increment, name varchar(255), primary key (id))  
    2. create table t_employee (id integer not null auto_increment, name varchar(255), companyid integer, primary key (id))  

    测试

    1. session.beginTransaction();  
    2. Company company=new Company();  
    3. company.setName("某某集团");  
    4. session.save(company);//这里必须要先save一下company,将之变成持久化状态否则会因为无法保存瞬时对象而报错  
    5. Employee employee1=new Employee();  
    6. employee1.setName("路人甲");  
    7. employee1.setCompany(company);  
    8. Employee employee2=new Employee();  
    9. employee2.setName("路人乙");  
    10. employee2.setCompany(company);  
    11. session.save(employee1);  
    12. session.save(employee2);  
    13. session.getTransaction().commit();  
    执行结果:
    1. Hibernate: insert into Company (id,name) values (?,?)  
    2. Hibernate: insert into Employee (id,name,companyid) values (?,?,?)  

    值得一提的是,如果我们没有在测试程序里面session.save(company),直接执行程序,我们会报错,但是解决办法绝不是只有这一种,我们还可以在员工Employee映射文件中的<many-to-one/>中配置cascade属性:

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssm.hibernate.Employee" table="t_employee">  
    3.             <id name="id" type="int">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.             <many-to-one name="company" column="companyid" cascade="save-update"/>  
    8.              <!--在这里配置cascade属性,表示两个对象之间的操作为联动关系-->  
    9.     </class>  
    10. </hibernate-mapping>  
    关于cascade的一些属性值分别是:persist, merge, delete, save-update, evict, replicate, lock, refresh

    二、一对多单向关联映射:

           同样适用上面的场景设定:国家规定一个员工只能在一个公司上班,但是一个公司可以拥有很多员工。这时候,针对公司来说,就是一对多关系了。像这种时候,我们就需要在公司类中添加一个对员工对象的集合了。这个集合可以是set、list、map、array数组的有关容器(其中set中的对象不可重复,相对性能也比较高,建议使用set)

    Po对象:Employee.java

    1. public class Employee{  
    2.     public int id;  
    3.     public String name;  
    4.     //getter、setter  
    5. }  

    Company.java

     

    1. public class Company{  
    2.     public int id;  
    3.     public String name;  
    4.     public Set<Employee> employees;  
    5.     //getter、setter  
    6. }  

    映射文件:Employee.hbm.xml

     

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Employee" table="t_employee">  
    3.             <id name="id" type="int">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.     </class>  
    8. </hibernate-mapping>  

    Company.hbm.xml

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Company" table="t_company">  
    3.             <id name="id">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.             <set name=employees>  
    8.         <key column="companyid"></key><!-- "多"的一方关联"一"的一方的外键 -->  
    9.         <one-to-many class="com.ssh.hibernate.Employee"/><!-- 一个Company对象对应多个Employee对象 -->  
    10.         </set>  
    11.     </class>  
    12. </hibernate-mapping>  

    测试:

    1. session.beginTransaction();  
    2. Employee employee1=new Employee();  
    3. employee1.setName("路人甲");  
    4. session.save(employee1)  
    5. Employee employee2=new Employee();  
    6. employee2.setName("路人乙");  
    7. employee2.save(employee2);  
    8. Set<Employee> employees=new HashSet<Employee>();  
    9. employees.add(employee1);  
    10. employees.add(employee2);  
    11. Company company=new Company();  
    12. company.setName("某某集团");  
    13. company.setEmployees(employees);  
    14. session.save(company);  
    15. session.getTransaction().commit();  
    事务提交数据插入之后,我们进行查询:
    1. session.beginTransaction();  
    2. Company company=(Company)session.load(Company.class,1);  
    3. System.out.println("公司名称:"+company.getName());  
    4. System.out.println("公司员工:");  
    5. for(Employee employee:company.getEmployees()){  
    6.     System.out.print(" "+employee.getName());  
    7. }  
    8. session.getTransaction().commit();  

    查询结果:

    1. Hibernate: select company0_.id as id0_0_, company0_.name as name0_0_ from t_company company0_   
    2.            where company0_.id=?  
    3. 公司名称:某某集团  
    4. 公司员工:Hibernate: select employees0_.companyid as company3_1_, employees0_.id as id1_,   
    5.            employees0_.id as id1_0_,employees0_.name as name1_0_ from t_employee employees0_   
    6.            where employees0_.companytid=?  
    7. 路人甲 路人乙  
    从控制台消息来看,还能延迟加载lazy,那如果我们把配置文件改为:

    Company.hbm.xml

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.    <class name="com.ssh.hibernate.Company" table="t_company">  
    3.        <id name="id">  
    4.           <generator class="native"/>  
    5.        </id>  
    6.        <property name="name"/>  
    7.        <set name=employees lazy="false"><!--如果这里将lazy设置成false,将禁止延迟加载,默认为true-->  
    8.        <key column="companyid"></key><!-- "多"的一方关联"一"的一方的外键 -->  
    9.        <one-to-many class="com.ssh.hibernate.Employee"/><!-- 一个Company对象对应多个Employee对象 -->  
    10.        </set>  
    11.   </class>  
    12. </hibernate-mapping>  

     

    三、多对一/一对多双向关联映射

    现在我们还是用上面的场景设定来实现一对多/多对一双向关联:

    Po对象:Company.java

     

    1. public class Company{  
    2.     public int id;  
    3.     public String name;  
    4.     public Set<Employee> employees;  
    5.     //getter、setter  
    6. }  
    Employee.java

     

    1. public class Employee {  
    2.     public int id;  
    3.     public String name;  
    4.     public Company company;  
    5.     //getter、setter  
    6. }  

    配置文件:Employee.hbm.xml

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Employee" table="t_employee">  
    3.             <id name="id" type="int">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.             <many-to-one name="company" column="companyid" not-null="true">  
    8.     </class>  
    9. </hibernate-mapping>  
    Company.hbm.xml
    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Company" table="t_company">  
    3.             <id name="id">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.             <set name="employees">  
    8.             <key column="companyid"></key>  
    9.             <one-to-many class="com.ssh.hibernate.Employee"/>  
    10.             </set>  
    11.     </class>  
    12. </hibernate-mapping>  
           如果你使用List(或者其他有序集合类),你需要设置外键对应的key列为 not null,让Hibernate来从集合端管理关联,维护每个元素的索引(通过设置update="false" and insert="false"来对另一端反向操作): 

    Employee.hbm.xml

    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Employee" table="t_employee">  
    3.             <id name="id" type="int">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.         <many-to-one name="company" column="companyid" not-null="true" insert="flase" update="false"/>  
    8.     </class>  
    9. </hibernate-mapping>  
    Company.hbm.xml
    1. <hibernate-mapping package="org.hibernate.test" >  
    2.     <class name="com.ssh.hibernate.Company" table="t_company">  
    3.             <id name="id">  
    4.                 <generator class="native"/>  
    5.             </id>  
    6.             <property name="name"/>  
    7.             <list name="employees">  
    8.             <key column="companyid" not-null="true"></key>  
    9.             <list-index column="employeeId"/>  
    10.             <one-to-many class="com.ssh.hibernate.Employee"/>  
    11.             </set>  
    12.     </class>  
    13. </hibernate-mapping>  

           假若集合映射的<key>元素对应的底层外键字段是NOT NULL的,那么为这一key元素定义not-null="true"是很重要的。不要仅仅为可能的嵌套<column>元素定义not-null="true",<key>元素也是需要的。

    四、总结:

    1、对于单向的一对多、多对一关联映射,建表时,都是在“多”的一端添加外键指向“一”的一端。而他们的不同点就是维护关系的不同,也可理解为主表变更,由谁指向谁的关系变了。

    2、对于双向的一对多/多对一来说,他们之间本就是互为指向的,只是要注意我们需用的方法的不同来针对不同的地方进行配置。使用set、list的时候,大体上是差不多的,关键就是使用list的时候,多对一从表的逐渐不可自己更添,而一对多从表主/外键id不能为空

  • 相关阅读:
    python学习笔记(1)
    一些有趣的使用function
    axios构建请求池处理全局loading状态&&axios避免重复请求
    axios构建缓存池存储基础数据
    文件下载方法
    关于 JS this
    前端 JS 获取 Image 图像 宽高 尺寸
    Html CSS transform matrix3d 3D转场特效
    Github 持续化集成 工作流 Npm包自动化发布
    远程 Linux(Ubuntu 18)添加字体
  • 原文地址:https://www.cnblogs.com/DoubleEggs/p/6257644.html
Copyright © 2020-2023  润新知