根據咱們的總結計劃,上篇文章咱們總結了有關於一對一映射相關知識,接下來,咱們進行下一個階段,一對多、多對一映射相關知識。html
場景設定:java
國家規定,一我的只能在一個公司上班,一個公司能夠擁有不少員工。咱們就利用這個場景,根據針對對象的不一樣,咱們分別來分析一下一對多、多對一關聯映射。程序員
1、多對一單向關聯映射
一、多對一單向關聯映射:對於員工(Employee)來講,他跟公司(Company)的對應關係就是多對一關係sql
Po對象:Employee.Java數據庫
- public class Employee {
- public int id;
- public String name;
- public Company company;
-
- }
Company.java
- public class Company{
- public int id;
- public String name;
-
- }
做爲程序員,咱們都知道在設計數據庫要在多對一的多那一面添加一的外鍵,因此咱們在員工類中,添加對公司類的引用。
映射文件:Employee.hbm.xml數組
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Employee" table="t_employee">
- <id name="id" type="int">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <many-to-one name="company" column="companyid"/>
- </class>
- </hibernate-mapping>
Company.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Company" table="t_company">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- </class>
- </hibernate-mapping>
執行程序自動生成表:
- create table t_company (id integer not null auto_increment, name varchar(255), primary key (id))
- create table t_employee (id integer not null auto_increment, name varchar(255), companyid integer, primary key (id))
測試:session
- session.beginTransaction();
- Company company=new Company();
- company.setName("某某集團");
- session.save(company);
- Employee employee1=new Employee();
- employee1.setName("路人甲");
- employee1.setCompany(company);
- Employee employee2=new Employee();
- employee2.setName("路人乙");
- employee2.setCompany(company);
- session.save(employee1);
- session.save(employee2);
- session.getTransaction().commit();
執行結果:
- Hibernate: insert into Company (id,name) values (?,?)
- Hibernate: insert into Employee (id,name,companyid) values (?,?,?)
值得一提的是,若是咱們沒有在測試程序裏面session.save(company),直接執行程序,咱們會報錯,可是解決辦法毫不是隻有這一種,咱們還能夠在員工Employee映射文件中的<many-to-one/>中配置cascade屬性:app
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssm.hibernate.Employee" table="t_employee">
- <id name="id" type="int">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <many-to-one name="company" column="companyid" cascade="save-update"/>
-
- </class>
- </hibernate-mapping>
關於cascade的一些屬性值分別是:persist, merge, delete, save-update, evict, replicate, lock, refresh
2、一對多單向關聯映射:
一樣適用上面的場景設定:國家規定一個員工只能在一個公司上班,可是一個公司能夠擁有不少員工。這時候,針對公司來講,就是一對多關係了。像這種時候,咱們就須要在公司類中添加一個對員工對象的集合了。這個集合能夠是set、list、map、array數組的有關容器(其中set中的對象不可重複,相對性能也比較高,建議使用set)ssh
Po對象:Employee.javaoop
- public class Employee{
- public int id;
- public String name;
-
- }
Company.java
- public class Company{
- public int id;
- public String name;
- public Set<Employee> employees;
-
- }
映射文件:Employee.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Employee" table="t_employee">
- <id name="id" type="int">
- <generator class="native"/>
- </id>
- <property name="name"/>
- </class>
- </hibernate-mapping>
Company.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Company" table="t_company">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <set name=employees>
- <key column="companyid"></key>
- <one-to-many class="com.ssh.hibernate.Employee"/>
- </set>
- </class>
- </hibernate-mapping>
測試:
- session.beginTransaction();
- Employee employee1=new Employee();
- employee1.setName("路人甲");
- session.save(employee1)
- Employee employee2=new Employee();
- employee2.setName("路人乙");
- employee2.save(employee2);
- Set<Employee> employees=new HashSet<Employee>();
- employees.add(employee1);
- employees.add(employee2);
- Company company=new Company();
- company.setName("某某集團");
- company.setEmployees(employees);
- session.save(company);
- session.getTransaction().commit();
事務提交數據插入以後,咱們進行查詢:
- session.beginTransaction();
- Company company=(Company)session.load(Company.class,1);
- System.out.println("公司名稱:"+company.getName());
- System.out.println("公司員工:");
- for(Employee employee:company.getEmployees()){
- System.out.print(" "+employee.getName());
- }
- session.getTransaction().commit();
查詢結果:
- Hibernate: select company0_.id as id0_0_, company0_.name as name0_0_ from t_company company0_
- where company0_.id=?
- 公司名稱:某某集團
- 公司員工:Hibernate: select employees0_.companyid as company3_1_, employees0_.id as id1_,
- employees0_.id as id1_0_,employees0_.name as name1_0_ from t_employee employees0_
- where employees0_.companytid=?
- 路人甲 路人乙
從控制檯消息來看,還能延遲加載lazy,那若是咱們把配置文件改成:
Company.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Company" table="t_company">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <set name=employees lazy="false">
- <key column="companyid"></key>
- <one-to-many class="com.ssh.hibernate.Employee"/>
- </set>
- </class>
- </hibernate-mapping>
3、多對一/一對多雙向關聯映射
如今咱們仍是用上面的場景設定來實現一對多/多對一雙向關聯:
Po對象:Company.java
- public class Company{
- public int id;
- public String name;
- public Set<Employee> employees;
-
- }
Employee.java
- public class Employee {
- public int id;
- public String name;
- public Company company;
-
- }
配置文件:Employee.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Employee" table="t_employee">
- <id name="id" type="int">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <many-to-one name="company" column="companyid" not-null="true">
- </class>
- </hibernate-mapping>
Company.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Company" table="t_company">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <set name="employees">
- <key column="companyid"></key>
- <one-to-many class="com.ssh.hibernate.Employee"/>
- </set>
- </class>
- </hibernate-mapping>
若是你使用List(或者其餘有序集合類),你須要設置外鍵對應的key列爲 not null,讓Hibernate來從集合端管理關聯,維護每一個元素的索引(經過設置update="false" and insert="false"來對另外一端反向操做):
Employee.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Employee" table="t_employee">
- <id name="id" type="int">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <many-to-one name="company" column="companyid" not-null="true" insert="flase" update="false"/>
- </class>
- </hibernate-mapping>
Company.hbm.xml
- <hibernate-mapping package="org.hibernate.test" >
- <class name="com.ssh.hibernate.Company" table="t_company">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name"/>
- <list name="employees">
- <key column="companyid" not-null="true"></key>
- <list-index column="employeeId"/>
- <one-to-many class="com.ssh.hibernate.Employee"/>
- </set>
- </class>
- </hibernate-mapping>
倘若集合映射的<key>元素對應的底層外鍵字段是NOT NULL的,那麼爲這一key元素定義not-null="true"是很重要的。不要僅僅爲可能的嵌套<column>元素定義not-null="true",<key>元素也是須要的。
4、總結:
一、對於單向的一對多、多對一關聯映射,建表時,都是在「多」的一端添加外鍵指向「一」的一端。而他們的不一樣點就是維護關係的不一樣,也可理解爲主表變動,由誰指向誰的關係變了。
二、對於雙向的一對多/多對一來講,他們之間本就是互爲指向的,只是要注意咱們需用的方法的不一樣來針對不一樣的地方進行配置。使用set、list的時候,大致上是差很少的,關鍵就是使用list的時候,多對一從表的逐漸不可本身更添,而一對多從表主/外鍵id不能爲空