【Hibernate框架】關聯映射(一對多,多對一)

根據咱們的總結計劃,上篇文章咱們總結了有關於一對一映射相關知識,接下來,咱們進行下一個階段,一對多、多對一映射相關知識。html

 

場景設定:java

       國家規定,一我的只能在一個公司上班,一個公司能夠擁有不少員工。咱們就利用這個場景,根據針對對象的不一樣,咱們分別來分析一下一對多、多對一關聯映射。程序員

 

1、多對一單向關聯映射

一、多對一單向關聯映射:對於員工(Employee)來講,他跟公司(Company)的對應關係就是多對一關係sql

Po對象:Employee.Java數據庫

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  1. public class Employee {  
  2.     public int id;  
  3.     public String name;  
  4.     public Company company;  
  5.     //getter、setter  
  6. }  
Company.java

 

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  1. public class Company{  
  2.     public int id;  
  3.     public String name;  
  4.     //getter、setter  
  5. }  
       做爲程序員,咱們都知道在設計數據庫要在多對一的多那一面添加一的外鍵,因此咱們在員工類中,添加對公司類的引用。

 

映射文件:Employee.hbm.xml數組

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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

 

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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>  
執行程序自動生成表:

 

 

[sql]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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))  

 

測試session

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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();  
執行結果:

 

 

[sql]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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屬性:app

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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

 

 

2、一對多單向關聯映射:

       一樣適用上面的場景設定:國家規定一個員工只能在一個公司上班,可是一個公司能夠擁有不少員工。這時候,針對公司來講,就是一對多關係了。像這種時候,咱們就須要在公司類中添加一個對員工對象的集合了。這個集合能夠是set、list、map、array數組的有關容器(其中set中的對象不可重複,相對性能也比較高,建議使用set)ssh

Po對象:Employee.javaoop

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  1. public class Employee{  
  2.     public int id;  
  3.     public String name;  
  4.     //getter、setter  
  5. }  

 

Company.java

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  1. public class Company{  
  2.     public int id;  
  3.     public String name;  
  4.     public Set<Employee> employees;  
  5.     //getter、setter  
  6. }  

 

映射文件:Employee.hbm.xml

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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>  

 

測試:

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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();  
事務提交數據插入以後,咱們進行查詢:

 

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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();  

 

查詢結果:

 

[sql]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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>  

 

 

3、多對一/一對多雙向關聯映射

 

如今咱們仍是用上面的場景設定來實現一對多/多對一雙向關聯:

Po對象:Company.java

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  1. public class Company{  
  2.     public int id;  
  3.     public String name;  
  4.     public Set<Employee> employees;  
  5.     //getter、setter  
  6. }  
Employee.java

 

 

[java]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  1. public class Employee {  
  2.     public int id;  
  3.     public String name;  
  4.     public Company company;  
  5.     //getter、setter  
  6. }  

 

配置文件:Employee.hbm.xml

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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
[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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

 

[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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
[html]  view plain copy
 print?在CODE上查看代碼片派生到個人代碼片
  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>元素也是須要的。

 

4、總結:

一、對於單向的一對多、多對一關聯映射,建表時,都是在「多」的一端添加外鍵指向「一」的一端。而他們的不一樣點就是維護關係的不一樣,也可理解爲主表變動,由誰指向誰的關係變了。

二、對於雙向的一對多/多對一來講,他們之間本就是互爲指向的,只是要注意咱們需用的方法的不一樣來針對不一樣的地方進行配置。使用set、list的時候,大致上是差很少的,關鍵就是使用list的時候,多對一從表的逐漸不可本身更添,而一對多從表主/外鍵id不能爲空

相關文章
相關標籤/搜索