1、单向的多对一关联映射(多个用户在同一个组内 User-Group)
(1)在多的一方,即用户的配置文件里,加入这句话
<many-to-one name="group" column="groupid" class="Group" cascade="all"></many-to-one>
并且在User实体类中需要以组的对象作为用户的属性的,这个是建立起组和用户关联的关键 private Group group; 并且获取get/set方法
(2)在少的一方,即组的配置文件里,不需要做任何修改
(3)测试类
创建两个新用户及一个组,注意如果不设置cascade属性,需要先保存group,在保存user
Group group = new Group();
group.setName("one");
User user1 = new User();
user1.setName("001");
user1.setGroup(group);
User user2 = new User();
user2.setName("002");
user2.setGroup(group);
//session.save(group);
session.save(user1);
session.save(user2);
图一 创建user和group表
图二 用户表(含有关联的外键,关联另一个表的主键)
图三 组表
2、双向的多对一关联映射(不同的部门有不同的员工)
(1)同样,先在多的一方,即员工的配置文件里,加入这句话
<many-to-one name="department" column="depart_id" class="Department" cascade="save-update"></many-to-one>
并且在Employee实体类中需要以部门的对象作为员工的属性的,这个是建立起部门和员工关联的关键 private Department department; 并且获取get/set方法
(2)配置双向,就必需要在部门的实体类里面用集合来存储员工
private Set<Employee> emps; 并且获取get/set方法
而且在部门的配置文件里配置set标签,而且反过来要用一对多来匹配员工的多对一
<set name="emps" cascade="all">
<key column="depart_id"/><!-- key指明了员工表中的外键-->
<one-to-many class="Employee" />
<!-- one-to-many指明了和哪个类进行一对多的映射 标签声明关联关系是一对多,class指定多方的实体类类型-->
</set>
<!--用set标签表示Department中的员工集合的属性,这个属性并没有映射到数据库中的部门表中,即部门表中,并没有emps这样的一个列。 -->
(3)测试类
(4)
图四 创建两个表
①插入数据
//插入四条数据
Department d = new Department();
d.setName("后勤");
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setName("001");
e2.setName("002");
e1.setDepartment(d);
e2.setDepartment(d);
session.save(d);
session.save(e1);
session.save(e2);
Department d2 = new Department();
d2.setName("主管");
Employee e3 = new Employee();
Employee e4 = new Employee();
e3.setName("1");
e4.setName("2");
e3.setDepartment(d2);
e4.setDepartment(d2);;
session.save(d2);
session.save(e3);
session.save(e4);
图五 向员工表插入数据
图六 向部门表插入数据
②查询数据
通过department查找employee
Department d = session.get(Department.class,2);
System.out.println("Deparement:"+d.getName());
System.out.println("DeptId:"+d.getId());
Set<Employee> employees = d.getEmps();
Iterator<Employee> it = employees.iterator();
while(it.hasNext()){
Employee employee = (Employee)it.next();
System.out.println("员工姓名:"+employee.getName());
}
图七 通过department查找employee
通过employee查找department
Employee e = (Employee)session.get(Employee.class,2);
System.out.println("员工姓名:"+e.getName()+"\t"+"员工所在部门:"+e.getDepartment().getName());
Employee e1 = (Employee)session.get(Employee.class,3);
System.out.println("员工姓名:"+e1.getName()+"\t"+"员工所在部门:"+e1.getDepartment().getName());
图八 通过employee查找department
③更新数据
更新数据,通过Employee进行更新
//将id为4的员工姓名修改为小明,并且将他所在的部门名称修改为主管部门
Employee e = (Employee)session.get(Employee.class,4);
e.setName("小明");
e.getDepartment().setName("主管部门");
session.saveOrUpdate(e);
图九 更新数据之后表的信息
更新数据,通过Department进行更新
//将id为1的部门名称修改为后勤部门,并且将此部门里的员工姓名为001员工修改为小王
Department d = (Department)session.get(Department.class,1);
d.setName("后勤部门");
Set<Employee> employees = d.getEmps();
Iterator<Employee> it = employees.iterator();
while(it.hasNext()){
Employee employee = (Employee)it.next();
System.out.println("员工姓名:"+employee.getName());
if("001".equals(employee.getName())){
employee.setName("小王");
}
}
图十 更新数据之后表的信息
④删除数据
删除员工,部门不会受影响
Employee e = (Employee)session.get(Employee.class,4);
session.delete(e);
输出部门,其内部的员工也会跟着被删除(先删除employee,在删除department)
Department d = (Department)session.get(Department.class,1);
session.delete(d);
3、单向的一对一主键关联映射(person-idcard)
(1)在IdCard的配置文件里面写:
<class name="IdCard" table="t_idcard" select-before-update="true" dynamic-update="true">
<id name="id" column="id">
<!--基于主键关联时,主键生成策略是foreign,表明根据关联类生成主键-->
<generator class="foreign">
<!--关联持久化类的属性名-->
<param name="property">person</param>
</generator>
</id>
<one-to-one name="person" constrained="true" cascade="all"></one-to-one>
</class>
(2)在Person的配置文件里不需要做任何修改
(3)测试类
①插入数据
Person p1 = new Person();
p1.setName("小明");
Person p2 = new Person();
p2.setName("小王");
IdCard id1 = new IdCard();
id1.setPerson(p1);
IdCard id2 = new IdCard();
id2.setPerson(p2);
session.save(id1);
session.save(id2);
图十一 插入数据
4、双向的一对一主键关联映射(person-idcard)
只需要在单向的基础上,在没有添加 <one-to-one> 标签的一方添加即可
注意:类要相互引用,同时在hibernate.cfg.xml中进行配置
单向关联和双向关联的区别主要在于单向只在一方配置而双向两方都要配置所以一对一双向关联比单向关联多了一个在文件中配置<one-to-one>
5、单向的一对一外键关联映射
基于外键关联的的单向一对一其实是单向多对一关联的一个特例。
只需要在映射文件的<many-to-one>标记中增加一个unique 属性即可,并且将unique 属性值设置为true(外键唯一性约束)
在定义基于外键的“单向一对一”关联时,可将<many-to-one>标记定义在任意一方,同时要在定义<many-to-one>标记的这一方所对应的持久类中添加导航到另一方的声明。
6、双向的一对一外键关联映射
在定义基于外键关联的“双向一对一”关联时,需要在关联双方分别添加一个对方类型的属性,用于实现双向导航。
Hibernate通过<many-to-one>标记和<one-to-one>标记结合使用来定义这种关联。
这种关联的映射文件与基于外键关联的单向一对一关联基本一致,区别在于在已有的<many-to-one>的基础上,在另一方增加<one-to-one>标记进行关联。
注意:在使用<one-to-one>标记的一方,必须指定property-ref属性(值为<many-to-one>里面的name属性),否则变成了使用主键关联。
7、双向的一对多关联映射
一对多关联映射,等同于双向的多对一关联映射。因为在双向的多对一中,多的一方需要配置<many-to-one>,而在少的一方,需要配置 <one-to-many>来匹配,而用set集合来存储多的一方的数据。
8、双向的多对多关联映射(student-teacher)
(1)在student的映射文件中加入:
<class name="Student" table="t_student" select-before-update="true" dynamic-update="true">
<id name="id" column="id">
<generator class="identity" />
</id>
<property name="name" column="s_name" length="25"/>
<set name="teacher" lazy="true" cascade="save-update" >
<key column="studentId"/>-->
<many-to-many class="Teacher" column="teacherId"/> </set>
</class>
(2)在teacher的映射文件中加入:
<class name="Teacher" table="t_teacher" select-before-update="true" dynamic-update="true">
<id name="id" column="id">
<generator class="identity"></generator>
</id>
<property name="name" column="t_name" length="22"/>
<set name="student" lazy="true" cascade="save-update" >
<key column="teacherId"/>
<many-to-many class="Student" column="studentId"/>
</set>
</class>
(3)在实体类中:
private Set<Teacher> teacher = new HashSet();
private Set<Student> student = new HashSet();
(4)测试类:
Student s1 = new Student();
s1.setName("aa");
Student s2 = new Student();
s2.setName("bb");
Teacher t1 = new Teacher();
t1.setName("AA");
Teacher t2 = new Teacher();
t2.setName("BB");
t1.getStudent().add(s1);
t1.getStudent().add(s2);
t2.getStudent().add(s1);
t2.getStudent().add(s2);
session.save(t1);
session.save(t2);
session.save(s1);
session.save(s2);
ts.commit();
图十二 插入数据