Hibernate学习-7-关联映射(一对多,多对一)
2016-12-08 18:03
344 查看
关联映射
需求分析
eg 1-
部门与员工的例子
一个部门有多个员工[一对多]
多个员工,属于一个部门[多对一]
eg 2-
一个项目多个开发人员
一个开发人员参与多个项目 [多对多]
一对多与多对一映射
一.需求分析
二.数据库
t_dept
字段:deptId deptName
t_employee
字段:empId empName salary dept_id
三.javabean
设计关键:通过一方维护到另一方
四.映射
Dept映射关键点
1.映射的集合属性:"emps"
2.指定集合属性对应的集合表:"t_employee"
3.指定集合表的外键字段
4.指定集合元素的类型
Employee映射的关键点
1.映射的部门属性: dept
2.映射的部门对象,对应的外键字段:dept_id
3.部门的类型
实例-保存数据-查询数据
总配置文件
Dept.java
相关映射配置
Employee.java
相关映射配置
测试类
结果
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
应用开发部
Hibernate:
select
employees0_.dept_id as dept4_0_1_,
employees0_.empId as empId1_,
employees0_.empId as empId1_0_,
employees0_.empName as empName1_0_,
employees0_.salary as salary1_0_,
employees0_.dept_id as dept4_1_0_
from
t_employee employees0_
where
employees0_.dept_id=?
[com.cx.entity.Employee@d35dea7, com.cx.entity.Employee@24313fcc]
Hibernate:
select
employee0_.empId as empId1_0_,
employee0_.empName as empName1_0_,
employee0_.salary as salary1_0_,
employee0_.dept_id as dept4_1_0_
from
t_employee employee0_
where
employee0_.empId=?
张三
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
应用开发部
Inverse属性
在维护关联关系的时候起作用。表示控制权是否转移。(在一的一方起作用)
inverse 控制反转
inverse = false不反转 有控制权
= true 控制反转 没有控制权 (不能主动维护另一方)
维护关联关系
1.保存数据
设计关联
如果设置控制反转,然后通过部门方维护关联关系。在保存部门的时候,同时保存员工,数据会保存,但关联关系不会维护,外键字段为NULL。
2.获取数据
无影响
3.解除关联关系
有影响
没有控制权无法接触关联关系,无法生成update语句,也不会报错
4.删除数据对关联关系的影响
有控制权,可以删除,先清空外键引用,再删除。
没控制权报错,无法删除。
测试代码
cascade属性
表示级联操作
none不级联操作 ,默认值
save-update级联保存或者更新
delete级联删除
save-update,delete 级联保存、更新、删除
all 同上
实例
需求分析
eg 1-
部门与员工的例子
一个部门有多个员工[一对多]
多个员工,属于一个部门[多对一]
eg 2-
一个项目多个开发人员
一个开发人员参与多个项目 [多对多]
一对多与多对一映射
一.需求分析
二.数据库
t_dept
字段:deptId deptName
t_employee
字段:empId empName salary dept_id
三.javabean
设计关键:通过一方维护到另一方
class Dept{ private int deptId; private String deptName; //部门对应多个员工 private Set<Employee> emps; } class Employee{ private int empId; private String empName; private double salary; //多个员工对应一个部门 private Dept dept; }
四.映射
Dept映射关键点
1.映射的集合属性:"emps"
2.指定集合属性对应的集合表:"t_employee"
3.指定集合表的外键字段
4.指定集合元素的类型
Employee映射的关键点
1.映射的部门属性: dept
2.映射的部门对象,对应的外键字段:dept_id
3.部门的类型
实例-保存数据-查询数据
总配置文件
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!--1.数据库连接配置--> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql:///learnHibernate</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">33269456.cx</property> <!-- 数据库方言配置,hibernate会根据不同的方言生成符合当前数据库语法的sql --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!--2.其他相关配置--> <!--2.1显示运行时的sql语句--> <property name="hibernate.show_sql">true</property> <!--2.2格式化sql--> <property name="hibernate.format_sql">true</property> <!--2.3自动建表,写好映射就可以--> <property name="hibernate.hbm2ddl.auto">update</property> <!--3.加载所有映射--> </session-factory> </hibernate-configuration>
Dept.java
package com.cx.entity; import java.util.HashSet; import java.util.Set; /** * Created by cxspace on 16-8-2. */ public class Dept { private int deptId; private String deptName; //一对多(一个部门对应多个员工) private Set<Employee> employees = new HashSet<>(); public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public Set<Employee> getEmployees() { return employees; } public void setEmployees(Set<Employee> employees) { this.employees = employees; } }
相关映射配置
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cx.entity"> <class name="Dept" table="t_dept"> <id name="deptId"> <generator class="native"></generator> </id> <property name="deptName" length="20"></property> <!-- 1.映射的集合属性:"emps" 2.指定集合属性对应的集合表:"t_employee" 3.指定集合表的外键字段 4.指定集合元素的类型 --> <!--table="t_employee",可以省略--> <set name="employees" table="t_employee"> <key column="dept_id"></key> <one-to-many class="Employee"></one-to-many> </set> </class> </hibernate-mapping>
Employee.java
package com.cx.entity; /** * Created by cxspace on 16-8-2. */ public class Employee { private int empId; private String empName; private double salary; private Dept dept; public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
相关映射配置
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cx.entity"> <class name="Employee" table="t_employee"> <id name="empId"> <generator class="native"></generator> </id> <property name="empName" length="20"></property> <property name="salary" type="double"></property> <!-- 多对一映射配置 Employee 映射关键点: 1. 映射的部门属性 : dept 2. 映射的部门属性,对应的外键字段: dept_id 3. 部门的类型 --> <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> </class> </hibernate-mapping>
测试类
package com.cx.test; import com.cx.entity.Dept; import com.cx.entity.Employee; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by cxspace on 16-8-2. */ public class Save { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } //保存,部门方 一对一方法操作 public void save(){ Session session = sf.openSession(); session.beginTransaction(); //部门对象 Dept dept = new Dept(); dept.setDeptName("应用开发部"); //员工对象 Employee emp_zs = new Employee(); emp_zs.setEmpName("张三"); Employee emp_ls = new Employee(); emp_ls.setEmpName("李四"); //关系 dept.getEmployees().add(emp_zs); dept.getEmployees().add(emp_ls); //保存 session.save(emp_zs); session.save(emp_ls); session.save(dept); session.getTransaction().commit(); session.close(); /* * Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_dept (deptName) values (?) Hibernate: update t_employee set dept_id=? where empId=? Hibernate: update t_employee set dept_id=? where empId=? * */ } //保存,员工方[多对一保存],效率更高 @Test public void save2(){ Session session = sf.openSession(); session.beginTransaction(); Dept dept = new Dept(); dept.setDeptName("综合部"); Employee emp_zs = new Employee(); emp_zs.setEmpName("张三"); Employee emp_ls = new Employee(); emp_ls.setEmpName("李四"); emp_zs.setDept(dept); emp_ls.setDept(dept); session.save(dept); session.save(emp_ls); session.save(emp_zs); session.getTransaction().commit(); session.close(); /* * * 结果 * * Hibernate: insert into t_dept (deptName) values (?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) Hibernate: insert into t_employee (empName, salary, dept_id) values (?, ?, ?) * * * */ } }
结果
package com.cx.test; import com.cx.entity.Dept; import com.cx.entity.Employee; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by cxspace on 16-8-2. */ public class Get { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(Dept.class) .addClass(Employee.class) // 测试时候使用 .buildSessionFactory(); } @Test public void get(){ Session session = sf.openSession(); session.beginTransaction(); //通过部门方获取另一方 // Dept dept = (Dept) session.get(Dept.class , 1); // System.out.println(dept.getDeptName()); // System.out.println(dept.getEmployees()); 结果
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
应用开发部
Hibernate:
select
employees0_.dept_id as dept4_0_1_,
employees0_.empId as empId1_,
employees0_.empId as empId1_0_,
employees0_.empName as empName1_0_,
employees0_.salary as salary1_0_,
employees0_.dept_id as dept4_1_0_
from
t_employee employees0_
where
employees0_.dept_id=?
[com.cx.entity.Employee@d35dea7, com.cx.entity.Employee@24313fcc]
//通过员工获取部门 Employee emp = (Employee)session.get(Employee.class,1); System.out.println(emp.getEmpName()); System.out.println(emp.getDept().getDeptName()); session.getTransaction().commit(); session.close(); 结果
Hibernate:
select
employee0_.empId as empId1_0_,
employee0_.empName as empName1_0_,
employee0_.salary as salary1_0_,
employee0_.dept_id as dept4_1_0_
from
t_employee employee0_
where
employee0_.empId=?
张三
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
应用开发部
} }
Inverse属性
在维护关联关系的时候起作用。表示控制权是否转移。(在一的一方起作用)
inverse 控制反转
inverse = false不反转 有控制权
= true 控制反转 没有控制权 (不能主动维护另一方)
维护关联关系
1.保存数据
设计关联
如果设置控制反转,然后通过部门方维护关联关系。在保存部门的时候,同时保存员工,数据会保存,但关联关系不会维护,外键字段为NULL。
2.获取数据
无影响
3.解除关联关系
有影响
没有控制权无法接触关联关系,无法生成update语句,也不会报错
4.删除数据对关联关系的影响
有控制权,可以删除,先清空外键引用,再删除。
没控制权报错,无法删除。
测试代码
package com.cx.test;
import com.cx.entity.Dept;
import com.cx.entity.Employee;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* Created by cxspace on 16-8-2.
*/
public class Inverse {
private static SessionFactory sf;
static {
sf = new Configuration()
.configure()
.addClass(Dept.class)
.addClass(Employee.class) // 测试时候使用
.buildSessionFactory();
}
//inverse对保存数据的影响
public void save(){
Session session = sf.openSession();
session.beginTransaction();
//部门对象
Dept dept = new Dept();
dept.setDeptName("运维部");
//员工对象
Employee emp_zs = new Employee();
emp_zs.setEmpName("张三");
Employee emp_ls = new Employee();
emp_ls.setEmpName("李四");
//关系
dept.getEmployees().add(emp_zs);
dept.getEmployees().add(emp_ls);
//inverse = true ,不会设置关联,此时的关联应该通过员工方来维护
//保存
session.save(emp_zs);
session.save(emp_ls);
session.save(dept);
session.getTransaction().commit();
session.close();
/*
*
*
*
Hibernate:
insert
into
t_employee
(empName, salary, dept_id)
values
(?, ?, ?)
Hibernate:
insert
into
t_employee
(empName, salary, dept_id)
values
(?, ?, ?)
Hibernate:
insert
into
t_dept
(deptName)
values
(?)
*
*
* */
}
//inverse属性,对获取数据的影响---无影响
public void get(){
Session session = sf.openSession();
session.beginTransaction();
Dept dept = (Dept) session.get(Dept.class,2);
System.out.println(dept.getDeptName());
System.out.println(dept.getEmployees());
session.getTransaction().commit();
session.close();
/*
*
*
*
* Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
综合部
Hibernate:
select
employees0_.dept_id as dept4_0_1_,
employees0_.empId as empId1_,
employees0_.empId as empId1_0_,
employees0_.empName as empName1_0_,
employees0_.salary as salary1_0_,
employees0_.dept_id as dept4_1_0_
from
t_employee employees0_
where
employees0_.dept_id=?
[com.cx.entity.Employee@d35dea7, com.cx.entity.Employee@24313fcc]
*
*
*
*
*
*
*
* */
}
public void removeRelation(){
Session session = sf.openSession();
session.beginTransaction();
Dept dept = (Dept)session.get(Dept.class,2);
dept.getEmployees().clear();
session.getTransaction().commit();
session.close();
/*
* inverse=true 没有控制权
*
*
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
*
*
*
inverse = false
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
Hibernate:
select
employees0_.dept_id as dept4_0_1_,
employees0_.empId as empId1_,
employees0_.empId as empId1_0_,
employees0_.empName as empName1_0_,
employees0_.salary as salary1_0_,
employees0_.dept_id as dept4_1_0_
from
t_employee employees0_
where
employees0_.dept_id=?
Hibernate:
update
t_employee
set
dept_id=null
where
dept_id=?
*
* */
}
@Test
public void deleteData(){
Session session = sf.openSession();
session.beginTransaction();
Dept dept = (Dept) session.get(Dept.class,1);
session.delete(dept);
session.getTransaction().commit();
session.close();
/*
inverse = true
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
Hibernate:
delete
from
t_dept
where
deptId=?
报错
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:189)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at com.cx.test.Inverse.deleteData(Inverse.java:217)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at org.junit.runner.JUnitCore.run(JUnitCore.java:130)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`learnHibernate`.`t_employee`, CONSTRAINT `FKFDCF5A195CFBCEF9` FOREIGN KEY (`dept_id`) REFERENCES `t_dept` (`deptId`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2054)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1467)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 32 more
inverse = false
正常删除
Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
Hibernate:
update
t_employee
set
dept_id=null
where
dept_id=?
Hibernate:
delete
from
t_dept
where
deptId=?
*/} }
cascade属性
表示级联操作
none不级联操作 ,默认值
save-update级联保存或者更新
delete级联删除
save-update,delete 级联保存、更新、删除
all 同上
实例
package com.cx.test;
import com.cx.entity.Dept;
import com.cx.entity.Employee;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* Created by cxspace on 16-8-2.
*/
public class Cascade {
private static SessionFactory sf;
static {
sf = new Configuration()
.configure()
.addClass(Dept.class)
.addClass(Employee.class) // 测试时候使用
.buildSessionFactory();
}
//级联保存
@Test
public void save(){
Session session = sf.openSession();
session.beginTransaction();
Dept dept = new Dept();
dept.setDeptName("人事部");
Employee emp_zs = new Employee();
emp_zs.setEmpName("张三");
Employee emp_ls = new Employee();
emp_ls.setEmpName("李四");
// 关系
dept.getEmployees().add(emp_zs);
dept.getEmployees().add(emp_ls);
//设置了级联只要保存部门
session.save(dept);
session.getTransaction().commit();
session.close();
/*
*
* Hibernate:
insert
into
t_dept
(deptName)
values
(?)
Hibernate:
insert
into
t_employee
(empName, salary, dept_id)
values
(?, ?, ?)
Hibernate:
insert
into
t_employee
(empName, salary, dept_id)
values
(?, ?, ?)
Hibernate:
update
t_employee
set
dept_id=?
where
empId=?
Hibernate:
update
t_employee
set
dept_id=?
where
empId=?
* */
}
public void delete(){
Session session = sf.openSession();
session.beginTransaction();
Dept dept = (Dept) session.get(Dept.class,5);
session.delete(dept);
session.getTransaction().commit();
session.close();
/*
*
* Hibernate:
select
dept0_.deptId as deptId0_0_,
dept0_.deptName as deptName0_0_
from
t_dept dept0_
where
dept0_.deptId=?
Hibernate:
select
employees0_.dept_id as dept4_0_1_,
employees0_.empId as empId1_,
employees0_.empId as empId1_0_,
employees0_.empName as empName1_0_,
employees0_.salary as salary1_0_,
employees0_.dept_id as dept4_1_0_
from
t_employee employees0_
where
employees0_.dept_id=?
Hibernate:
update
t_employee
set
dept_id=null
where
dept_id=?
Hibernate:
delete
from
t_employee
where
empId=?
Hibernate:
delete
from
t_employee
where
empId=?
Hibernate:
delete
from
t_dept
where
deptId=?
*
* */} }
相关文章推荐
- hibernate学习 关联映射(多对一,一对多)
- Hibernate视频学习笔记(7)多对多关联映射
- Eclipse快速上手Hibernate--7. 关联映射(一对多) (2)
- Hibernate学习18 -- 关联映射8 -- 继承映射2 -- 父类存储在一张表,子类分别存储一张表
- Hibernate学习手记(5)--关联映射
- Hibernate学习22 -- 关联映射12 -- 集合映射
- Hibernate关联映射-----一对多关联和多对一关联
- Hibernate学习16 -- 关联映射6 -- 多对多关联2 -- 多对多关联双向
- Hibernate学习19 -- 关联映射9 -- 继承映射3 -- 子类分别存储一张表
- Eclipse快速上手Hibernate--7. 关联映射(一对多) (2)
- hibernate映射一对多,双向关系[关联自身],初学例子四
- Eclipse快速上手Hibernate--7. 关联映射(一对多) (3)
- Eclipse快速上手Hibernate--7. 关联映射(一对多) (2)(摘自javaxmj的blog)
- Hibernate学习20 -- 关联映射10 -- 组件映射(component)
- Hibernate视频学习笔记(4)多对一及一对一关联映射
- Eclipse快速上手Hibernate--7. 关联映射(一对多) (1)
- Eclipse快速上手Hibernate--7. 关联映射(一对多) (1)(摘自javaxmj的blog)
- Hibernate学习12 -- 关联映射2 -- 一对一关联1 -- 一对一主键关联
- Hibernate学习23 -- 关联映射13 -- 动态模式映射
- Hibernate学习21 -- 关联映射11 -- 复合主键映射(composite-id)