关联关系是用到的最多的一种关系,非常重要,在内存中反映为实体关系,映射到DB中主键外键关系,实体间的关联,即对外键的维护,关联关系的发生,即对外键数据的改变。

在这里就不赘述什么是外键什么是主键了。

一丶关联的的数量

实体对象间的关联从数量上可以划分为

  • 1:1(一对一)
  • 1:N(一对多)
  • N:1(多对一)
  • M:N(多对多)

二丶关联属性

Java代码实体定义中,声明另一个实例类类型或其集合类型的属性,称为关联属性。

public class Department{
private Integer DepartNo;
private String DepartName;
private Set<Employee> employee;//这个就是关联的属性
}

三丶关联方向

(1)单向关联

指具有关系关联的实体对象间的加载与访问关系是单向的,只有一个实体对象可以加载和访问对方,但是对方看不到另一方的。

(2)双向关联

指具有关系关联的实体对象间的加载与访问时双向的,即,任何一方均可加载和访问另一方。

四丶级联操作

级联操作分为:级联保存,级联删除,级联更新......

如果现在有部门表和员工表,两个表之间是关联的。那么当添加部门的时候,也会将这个部门的员工添加到员工表,当添加员工的时候也会将员工添加到部门表中。

删除,更新同理。

五丶关联关系维护

(1)Java代码上的关联关系维护

通过实体类来维护

(2)数据库上的关联关系维护

通过外键来维护

当我们操作数据(例如插入save)的时候都会先操作对方表的数据:

如果我们插入的是单方的数据,它底层会先插入多方的数据(无外键),然后插单方的数据。所以最后外键使用update更新

如果我们向多方插入数据,应该先插入单方数据,然后再插入多方,所以数据库里面使用inert语句维护关联关系。所以最后外键使用insert更新

说了那么多我们接下来就来使用Hibernate实现这些关联:

六丶一对多单向关联(“一”能加载和访问“多”)

第一步:

创建两个关联的实体类

//Employee实体类
public class Employee {
private Integer id;
private String ename;
public Employee() {
super();
} public Employee(String ename) {
super();
this.ename = ename;
}
}
//这里省略了setter,getter方法
//部门实体类
public class Department {
private Integer id;
private String dname;
private Set<Employee> employees; public Department() {
super();
} public Department(String dname) {
super();
this.dname = dname;
}
}
//这里省略了setter,getter方法

第二步:

配置映射文件

Employee映射文件:

Department映射文件



在Department映射文件里面的Employee成员需要使用set标签,要关联表的外键名字(这样自动建出来的表会多一个外键名字叫做dept),最后还要指明关联关系为一对多,并且支出“多”对应的实体类路径。

第三步:

别忘了在主配置文件中注册映射文件(博主就把这茬给忘了)

第四步:

完成测试

public class TestOneToMany {
public static void main(String[] args) {
Session session = hbnUtil.getSession();
session.beginTransaction();
//新建三个员工对象
Employee employee1 = new Employee("张三");
Employee employee2 = new Employee("李四");
Employee employee3 = new Employee("王二");
//新建一个Employee类型的HashSet
Set<Employee> employees = new HashSet<Employee>();
//将员工保存到一个HashSet中
employees.add(employee1);
employees.add(employee2);
employees.add(employee3);
//新建一个部门对象
Department dept = new Department("宣传部");
//将员工保存到部门对象中
dept.setEmployees(employees);
//将员工持久化到DB中(这个时候还没有外键)
session.save(employee1);
session.save(employee2);
session.save(employee3);
//将dept持久化到DB中(这个时候Hibernate为Employee表Update上了外键)
session.save(dept);
//提交事务
session.getTransaction().commit();
} }

大家看上面的测试方法是不是觉得这个代码很臃肿?那接下来我们来进行优化一下:

有同学会有疑问,之前不是提到过可以进行级联操作吗,为什么持久化dept之前还要持久化employee呢?

对,所以我们可以对配置文件的改进来使得可以实现级联操作,我们来改一下:

<!--在“一”Department的配置文件set标签内添加cascade(我这里填的是all表示所有级联操作,包含保存和删除等等)-->
<set name="employees" cascade="all">
<key column="dept"/>
<one-to-many class="entity.Employee"/>
</set>

添加过后我们测试代码就可以删去一下三行代码:

        session.save(employee1);
session.save(employee2);
session.save(employee3);

下面是我们在数据库中生成的结果:



这样就完成了我们的一对多关系单向关联映射。

说完了一对多单向关联,我们再来看看一对多双向关联。

============================================

七丶一对多双向关联(同时也是多对一双向关联)

双向关联实在单向关联的基础上进行修改:

第一步:

修改实体类,修改“多”的实体类,我们之前单向关联的时候Employee实体类里面没有dept(部门)字段,数据库中生成的dept是由Hibernate根据Department的映射文件来生成的dept字段。

所以我们要在Employee实体类中添加dept字段。

第二步:

修改Employe配置文件:

<class name="entity.Employee" >
<id name="id">
<generator class="native"/><!-- increment -->
</id>
<property name="ename"/>
<many-to-one name="dept" class="entity.Department" cascade="all" column="dept"/>
<!--name指的是Employee实体类中的字段;column="dept"这个指的是Department配置文件里的column="dept" 如果都相同(Employeedept字段和Department所指定的column值相同)可以省略column="dept",否则不能省略,省略过后会Hibernate会根据这里指定的name值在数据库里多生成一个字段,下面举个栗子-->
</class>

Department配置文件,column指定为dept1

Employee配置文件,没有指定column

然后我们运行测试类,看看生成结果:



结果多生成了一个

但是如果我们再Department 的column指定的就是dept,且Employee的字段为dept,Employee配置文件中也是指定的dept,那么久只会生成一个dept(限于篇幅就不演示了,有兴趣的小伙伴可以自己试试)。

上面说了那么多也没将测试类给出,其实测试类和之前我们的单向关联是相同的,但是值得一提的是双向关联真的可以双向了

	Employee employee1 = new Employee("张三");

	Set<Employee> employees = new HashSet<Employee>();

	employees.add(employee1);

	Department dept = new Department("宣传部");

	//dept.setEmployees(employees);

	employee1.setDept(employees);

	session.save(employee1);
/*可以看出这次我们保存的是employee1,但是我们同样将两张表的信息都更新了(在保存之前,一定要调用employee1.setDept(employees)方法)*/

处了上面的意外还要提到一个属性:inverse,双向关联中这个属性可以存在于一方的配置文件set标签中,默认是:inverse=“false”,表示“一”方维护关联关系,当将inverse设置为“true”时,“一”方将放弃关联关系。

=======================================

八丶自关联

自关联就是自己和自己关联,例如一个员工表,里面不仅有普通员工,也有非普通员工(Boss)。所以Boss和员工就在同一张Employee表中,但是不同的是,每个普通员工都有一个Boss,但是Boss没有Boss。

接下来我们看看Hibernate中我们是怎么样实现自关联的:

第一步:

定义实体类

public class Employee {
private Integer id;
private String name;
private Employee boss;
private Set<Employee> commonemp; public Employee() {
super();
} public Employee(String name) {
this.name = name;
}
}//省略了getter,setter方法

第二步:

配置映射文件

	<class name="entity.Employee" >
<id name="id">
<generator class="native"/><!-- increment -->
</id>
<property name="name"/> <many-to-one name="boss" class="entity.Employee" cascade="all" column="boss"/>
<set name="commonemp" cascade="all">
<key column="boss"/>
<one-to-many class="entity.Employee"/>
</set>
</class>

第三步:

Test

	    //新建一个老板
Employee boss = new Employee("老板");
//新建一个普通员工
Employee commonEmp = new Employee("员工");
//获得set集合,并将员工添加到老板对象中
Set<Employee> set = new HashSet<Employee>();
set.add(commonEmp);
//持久化
session.save(boss);

结果:

因为我们保存的是boss,所以它的boss项为null。

因为这里是双向自关联的,我们再来测试下插入员工:

	    //新建一个老板
Employee boss = new Employee("老板");
//新建一个普通员工
Employee commonEmp = new Employee("员工");
//为员工指定老板
commonEmp.setBoss(boss);
//持久化
session.save(commonEmp);

结果:

这样就插入了员工,他的boss栏为1,即他的老板为id为1。

九丶多对一单向关联

说完一对多(多对一)双向关联过后就很好做多对一单向关联了。

第一步:

只要将“一”这一方的set集合删除(连带setter,getter方法,不删也不影响),还有配置文件里的set标签。

Department实体类:

public class Department {
private Integer id;
private String name; public Department() {
super();
} public Department(String name) {
this.name = name;
//省略了getter,setter方法
}

Department(一方映射配置文件)

	<class name="entity.Department" >
<id name="id">
<generator class="native"/><!-- increment -->
</id>
<property name="name"/>
</class>

Employee实体类:

public class Employee {
private Integer id;
private String name;
private Department dept;
public Employee() {
super();
}
public Employee(String name) {
super();
this.name = name;
}
}

Employee(多方)映射配置文件

	<class name="entity.Employee" >
<id name="id">
<generator class="native"/><!-- increment -->
</id>
<property name="name"/>
<many-to-one name="dept" class="entity.Department" cascade="all" /><!--因为不用自动生成主键,并且和Department里面column设置一致,所以省略column-->
</class>

Test:

		Department dept = new Department("宣传部");

		Employee emp = new Employee("张三");

		emp.setDept(dept);

		session.save(emp);

我们这就完成了多对一单向关联。

最后一个便是我们本篇文章的难点了(多对多关系关联映射):

=======================================

十丶多对多单向关联

什么是多对多?

现在有多个学生和多门课程,一个学生可以选几门课程,同时一门课也可以被多个学生选。

例如现在有两个学生张三,李四。有三门课,Java SE,JavaEE,Android。张三选JavaSE和JavaEE,李四选JavaSE和Android。

这样的关系叫做多对多关系。

我们都知道多对多关系在数据库中是通过中间表来完成它们之间的关联的,那么Hibernate怎么关联,我们接着往下看:

//学生实体类
public class Student {
private Integer sid;
private String sname;
private Set<Course> courses;
public Student() {
super();
} public Student(String sname) {
super();
this.sname = sname;
}
}//省略了setter,getter方法
//课程实体类
public class Course {
private Integer cid;
private String cname;
public Course() {
super();
}
public Course(String cname) {
this.cname = cname;
}
}//省略了getter,setter方法
<!--Course映射配置文件-->
<class name="entity.Course" >
<id name="cid">
<generator class="native"/><!-- increment -->
</id>
<property name="cname"/>
</class>
	<!--Student映射配置文件-->
<class name="entity.Student" >
<id name="sid">
<generator class="native"/><!-- increment -->
</id>
<property name="sname"/>
<set name="courses" cascade="all" table="middle"> <!--name为Student内的courses,这里面要加一个table属性,创建一个关联表middle-->
<key column="sid"/><!--设置关联表middle的主键,在数据库中middle的主键同时也是外键和student关联-->
<many-to-many class="entity.Course" column="cid"/><!--这里设置和Course多对多关系,在数据库中column="cid"为关联表的外键,和course关联-->
</set>
</class>

Test:

		//新建课程
Course c1 = new Course("Java SE");
Course c2 = new Course("Java EE");
Course c3 = new Course("Android");
//新建学生
Student s1 = new Student("张三");
Student s2 = new Student("李四");
//新建两个集合
Set<Course> courses1 = new HashSet<Course>();
Set<Course> courses2 = new HashSet<Course>();
//将课程放入集合
courses1.add(c1);
courses1.add(c2);
courses2.add(c1);
courses2.add(c3);
//为学生添加课程集合
s1.setCourses(courses1);
s2.setCourses(courses2);
//持久化
session.save(s1);
session.save(s2);

数据库结果:







这里的一对多单向关联有学生维持关联关系,从数据库结果我们也可以看出,学生是“一”,middle是“多”,课程是“一”,所以多对多就是由两个一对多组成。student和middle表关系中,sid是外键也是主键。

course和middle表关系中,cid是外键。

十一丶多对多双向关联

双向关联是在单向关联的基础上改一下就好:

将Course实体类添加一个Set集合



配置文件修改成这样:



上面配置文件key为当前实体类的cid这样的配置文件你会发现数据库中新建的middle表有两个主键:



这样和单向关联就有很大的差别了,这里的middle在和course和student的关系中主键是不同的(当然你也可以认为是相同的,毕竟两个都是主键,这就是和单向关联的一个差别)

Test:

//新建课程
Course c1 = new Course("Java SE");
Course c2 = new Course("Java EE");
Course c3 = new Course("Android");
//新建学生
Student s1 = new Student("张三");
Student s2 = new Student("李四");
//新建三个集合,放学生
Set<Student> c1s = new HashSet<Student>();
Set<Student> c2s = new HashSet<Student>();
Set<Student> c3s = new HashSet<Student>();
//将选c1课程的放c1s中
c1s.add(s1);
c1s.add(s2);
//将选c2课程的放入c2s中
c2s.add(s1);
//将选c3课程的放入c3s中
c3s.add(s2); //为课程关联学生
c1.setStudents(c1s);
c2.setStudents(c2s);
c3.setStudents(c3s); //持久化课程
session.save(c1);
session.save(c2);
session.save(c3);

测试的结果和单向的结果是一样的。

双向关联,双方都可以维护关联关系

到这儿我们的关联关系映射就结束了,当然我们Hibernate的只是还没学完,未完待续.

如果错误,不吝赐教。

Hibernate学习---关联关系映射的更多相关文章

  1. Hibernate之关联关系映射(一对一主键映射和一对一外键映射)

    1:Hibernate的关联关系映射的一对一外键映射: 1.1:第一首先引包,省略 1.2:第二创建实体类: 这里使用用户信息和身份证信息的关系,用户的主键编号既可以做身份证信息的主键又可以做身份证信 ...

  2. 框架之 hibernate之关联关系映射

    案例:完成CRM的联系人的保存操作 需求分析 1. 因为客户和联系人是一对多的关系,在有客户的情况下,完成联系人的添加保存操作 技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. J ...

  3. Hibernate的关联关系映射

    技术分析之Hibernate的关联关系映射之一对多映射(重点)        1. JavaWEB中一对多的设计及其建表原则        2. 先导入SQL的建表语句                 ...

  4. Hibernate 实体关联关系映射----总结

    在我看来,Hibernate提供这些映射关系,常用就是一对一和多对一,并且在能不用连接表的时候尽量不要用连接表.多对多会用到,如果用到了,应该首先考虑底层数据库设计是否合理.   在实际开发中,在Hi ...

  5. Hibernate之关联关系映射(一对多和多对一映射,多对多映射)

    ~~~接着之前的Hibernate框架接着学习(上篇面试过后发现真的需要学习一下框架了,不然又被忽悠让去培训.)~~~ 1:Hibernate的关联映射,存在一对多和多对一映射,多对多映射: 1.1: ...

  6. Hibernate 实体关联关系映射【转】

    Hibernate关联关系映射目录│ ├─单向关联│  ├─  一对一外键单向关联│  ├─  一对一主键单向关联│  ├─  一对一连接表单向关联│  ├─  一对多外键单向关联│  ├─  一对多 ...

  7. Hibernate 实体关联关系映射(转载)

    原文链接地址:http://lavasoft.blog.51cto.com/62575/39398/ Hibernate:Hibernate关联关系映射实例速查   Hibernate关联关系映射目录 ...

  8. Hibernate学习之映射关系

    一.Hibernate多对一关联映射:就是在“多”的一端加外键,指向“一”的一端. 比如多个学生对应一个班级,多个用户对应一个级别等等,都是多对一关系. 1.“多”端实体加入引用“一”端实体的变量及g ...

  9. Hibernate学习笔记--映射配置文件详解

    参考资料: http://blog.163.com/hzd_love/blog/static/13199988120108265317988/ http://www.cnblogs.com/often ...

随机推荐

  1. Android Studio 使用笔记:[转] Mac下修改Android Studio 所用的JDK版本

    原文链接:http://www.jianshu.com/p/d8d1d72d0248# 最近项目从Eclipse+Ant构建模式转移到了Android Studio+Gradle构建模式,自然的JDK ...

  2. hdu3208 Power of Integer

    /** 题目:H - Power of Integer 链接:https://vjudge.net/contest/152887#problem/H 题意:给出区间[a, b],问你区间[a, b]所 ...

  3. 以css为例谈设计模式

    什么是设计模式? 曾有人调侃,设计模式是工程师用于跟别人显摆的,显得高大上:也曾有人这么说,不是设计模式没用,是你还没有到能懂它,会用它的时候. 先来看一下比较官方的解释:"设计模式(Des ...

  4. dropdown多选下拉框

    写好了一个dropdown多选框.直接粘下面代码就能用 效果展示: temp2.jsp <%@page import="com.util.LabelCacheManager" ...

  5. PHP : ActiveRecord实现示例

    先简单介绍一下Active Record: Active Record(中文名:活动记录)是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录.Acti ...

  6. SVN如何新建用户并分配权限

    打开SVN服务端,找到特定的项目目录,单击右键,然后点击属性:   在弹出的页面中,点击增加:   在增加的页面中,你可以选择之前已经创建的用户,也可以重新创建用户名和密码:   如果是选择已经有的用 ...

  7. phantom的使用

    phantom页面加载 通过Phantomjs,一个网页可以被加载.分析和通过创建网页对象呈现,访问我的博客园地址:http://www.cnblogs.com/paulversion/p/83938 ...

  8. go build说明

    go build命令用于编译我们指定的源码文件或代码包以及它们的依赖包. 例如,如果我们在执行go build命令时不后跟任何代码包,那么命令将试图编译当前目录所对应的代码包.例如,我们想编译goc2 ...

  9. delphi小知识 点(if条件符,to_date)

    1.if条件 与:and 或:or 不等于:<> 等于:= 例子: if(j=1)and(nFH<>0) then begin tLCH:=Trim(copy(tSAMPLEI ...

  10. Storm 提交任务过程详解 (不对地方麻烦指正)

    1.使用的是Storm中自带的一个测试jar包 提交下这任务到storm中去 storm jar /usr/local/app/storm/examples/storm-starter/storm-s ...