zoukankan      html  css  js  c++  java
  • 【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不能为空

  • 相关阅读:
    【codecombat】 试玩全攻略 第九关 循环又循环
    【codecombat】 试玩全攻略 第十三关 已知敌人
    【codecombat】 试玩全攻略 第十一关 再次迷宫经历
    【codecombat】 试玩全攻略 第六关 cell commentary
    【codecombat】 试玩全攻略 第八关 火舞
    【codecombat】 试玩全攻略 第十二关 恐惧之门
    【codecombat】 试玩全攻略 第十四关 已知敌人
    苹果apns推送总结
    Xcode 提升速度小技巧
    UITextField 限制输入字数
  • 原文地址:https://www.cnblogs.com/DoubleEggs/p/6257644.html
Copyright © 2011-2022 走看看