一、一对多 vs 多对一
相同点:映射原理是一致的,都是在多的一端加入一个外键,指向一的一端
双向关联是一致的。
区别在于维护的关系不同——即单向关联
多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
有了这些认识,我们来看看具体的实现吧。
二、一对多
形如班级和学生之间的关系就是一对多,一个班级有多个学生。关系图
来看一下实现过程:
1、单向Classes--->Student
被关联的对象student,不用做改动。
Class 实体类
public class Classes {
private int id;
private String name;
private Set students;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set getStudents() {
return students;
}
public void setStudents(Set students) {
this.students = students;
}
}
class
映射文件
<hibernate-mapping>
<class name="cassie.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students">
<!-- <key column="classesid" not-null="true"/> -->
<key column="classesid"/>
<one-to-many class="cassie.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>
单向关联维护关系存在缺陷:
1、因为多的一端Student不知道Classes的存在(也就是Student没有维护与Classes的关系),所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,则将无法保存数据。
2、另外因为Student不维护关系,而Classes维护关系,Classes就会发出多余的update语句,保证Classes和Student有关系,这样加载Classes的时候才可以把该Classes对应的学生加载上来
正因为如此,我们引入了双向关联,一对多的双向关联的出现是为了克服单向的权限而出现的,不是应需求驱动的。
2、双向的实现
映射方式:
在一的一端的集合上采用<key>标签,在多的一端加入一个外键
在多的一端采用<many-to-one>标签
注意:<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱。
Class 不用改动,现在改动student类
student类
public class Student {
private int id;
private String name;
private Classes classes;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
}
Student.hbm.xml
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Student" table="t_student">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="classes" column="classesid"/>
</class>
</hibernate-mapping>
3、inverse属性
inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为
false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端
维护关系,本端失效。
一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true。
为什么呢?是为了节省数据库资源。
双方如果都可以维护关系,在进行insert语句时,另一方就势必会有update语句发出,所以省却不必要的update语句,我们一般建议在一对多双向关联关系中,将一方的inverse属性设置为true,即将主外键的关系交由多方来维护。
打个比方:在一个公司中,是老板认识所有的员工容易,还是所有员工认识老板容易?
所以在这,我们需要把class维护关系失效
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true">
<!--
<key column="classesid" not-null="true"/>
-->
<key column="classesid"/>
<one-to-many class="com.bjpowernode.hibernate.Student"/>
</set>
</class>
</hibernate-mapping>
三、多对一
实现:在多的一端加入一个外键,指向一的一端。
约定标签:many-to-one
关系图
单向实现
User实体类
public class User {
private int id;
private String name;
private Group group;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
}
User.hbm.xml
<hibernate-mapping>
<class name="com.bjpowernode.hibernate.User" table="t_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="group" column="groupid" cascade="save-update"/>
</class>
</hibernate-mapping>
不难发现,多对一的单向的设置,其实就是一对多双向的一部分中的“多的一段的"设置。所以双向多对一,即一对多的双向。这里就不在赘述。
结语:一对多,和多对一的关系是最常见的关系。双向关联,两者无区别,单向关联的时候,一定要谨慎。