从今天开始,就要开始学习关联关系了,其中关联关系,分为如下几种:
1、一对一关联关系
2、一对多关联关系
3、多对一关联 关系
4、多对多关联关系
总的来说,虽然有如上几种关联方式,但是我们可以理解它只是1中关联方式,就 多对多关联,这是因为其他的关联方式都可以理解为此关联方式的一种特殊方式。
其中,上面提到的关联关系,都存在单向和双向的关联关系。
这篇博文主要介绍下一对一关联关系。
一对一外键关联关系包括:
1、一对一单向外键关联关系的Annotation实现
2、一对一单向外键关联关系的xml实现
3、一对一双向外键关联关系的Annotation实现
4、一对一双向外键关联关系的xml实现
与外键相对应的还有主键关联。
我们生活中有很多一对一关联的例子,例如:”一夫一妻制”就是一对一的关联关系。一个学生有一个身份证也是一个一对一的关联关系。
一对一关联使用注解@OneToOne来进行修饰。
下面就以:”一夫一妻制”这个例子来进行分析。
Wife实体类
@Entity
public class Wife {
private int id;
private String name;
@Id
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;
}
}
Husband实体类
Huaband实体类中有一个Wife类的引用wife,并在getWife方法上添加了注解@OneToOne,如果我们想指定外键的名字,则通过注解@JoinColumn(name=”wifeId”)来指定,其中wifeId就是我们这个例子中指定的名字。
Husband实体类的具体代码如下:
@Entity
public class Husband {
private int id;
private String name;
private Wife wife;
@Id
@GeneratedValue
public int getId() {
return id;
}
@OneToOne
@JoinColumn(name="wifeId") //指定外键的名字为wifeId
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
hibernate.cfg.xml文件内容不再贴出,与前几篇博文的内容类似。
测试代码如下:
public class TeacherTest {
@Test
public void testSchema(){
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();
Metadata metadata = new MetadataSources(serviceRegistry).buildMetadata();
SchemaExport schemaExport = new SchemaExport();
schemaExport.create(EnumSet.of(TargetType.DATABASE), metadata);
}
}
SchemaExport类主要用于将SQL语句输出到数据库中。
在控制台我们会看到如下的主要输出信息,其中包括两条建表语句,一条插入外键的语句。
以上,这样我们就通过Annotation建立了Husband和Wife一对一单向外键关联关系。
现在换一个例子,以一个学生有一个身份证这样一个一对一的关联关系来举例分析。
Student类
package com.hibernate.model;
public class Student {
private int id;
private String name;
// id 、num、 student的getter和setter方法省略
}
IdCard类
public class IdCard {
private int id;
private String num;
private Student student;
// id 、num、 student的getter和setter方法省略
}
IdCard.hbm.xml文件内容如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="IdCard" table="idcard" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="num" column="num"/>
<!-- 一对一的关联在xml文件中用many-to-one 和unique="true"联合来进行限制 -->
<many-to-one name="student" column="studentId" unique="true"></many-to-one>
</class>
</hibernate-mapping>
上面的代码中:一对一的关联关系在如下的代码中指定:
<many-to-one name="student" column="studentId" unique="true"></many-to-one>
Student.hbm.xml文件内容如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Student" table="student" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
这样我们就将Student和IdCard通过外键建立了一对一的关联。
测试文件与第一个例子的测试文件一样,这里不再贴出。
Student类
类中有一个Wife的引用wife。
@Entity
public class Husband {
private int id;
private String name;
private Wife wife;
@Id
@GeneratedValue
public int getId() {
return id;
}
@OneToOne
@JoinColumn(name="wifeId") //指定外键的名字为wifeId
public Wife getWife() {
return wife;
}
//name属性的get方法和所有属性的set方法均省略。
}
Wife实体类
@Entity
public class Wife {
private int id;
private String name;
private Husband husband;
@OneToOne(mappedBy="wife") //这里的意思为:外键的关联是在Husband的wife对象上面来做,即Husband是主导
public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
@Id
public int getId() {
return id;
}
//name属性的get方法和所有属性的set方法均省略。
}
Wife类中也有一个Husband类的引用,并且需要在getHusband()方法前用@OneToOne(mappedBy=”wife”)进行注解。如果只用@OneToOne而不使用参数的注解,则会为表Husband和Wife都会建立一个外键的关联,有冗余。
最好的方法:凡是双向关联中,必须要设置@OneToOne(mappedBy=”XXX”)。
即Student类和IdCard类中均有对方的一个引用,且在IdCard.hbm.xml文件中的内容与一对一的内容不变,如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="IdCard" table="idcard" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="num" column="num"/>
<!-- 一对一的关联在xml文件中用many-to-one 和unique="true"联合来进行限制 -->
<many-to-one name="student" column="studentId" unique="true"></many-to-one>
</class>
</hibernate-mapping>
而在Student.hbm.xml文件中的内容,有一点变化,
加上了
<one-to-one name="idCard" class="IdCard" property-ref="student"/>
完整内容如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Student" table="student" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
<!--property-ref的参数是本类所关联的类IdCard类中的Student的引用 -->
<one-to-one name="idCard" class="IdCard" property-ref="student"/>
</class>
</hibernate-mapping>
注意:在数据库中,单向和双向是没有区别的,但是,在实体类中的对应关系是有区别的。
在外键关联中,例如,会在Husband表中生成一个wifeId的字段作为外键,而主键关联则不会生成其它任意的字段。
一对一单向主键关联Annotation实现
用如下的注解来实现:
@PrimaryKeyJoinColumn //用此注解表示主键关联
@Entity
public class Husband {
private int id;
private String name;
private Wife wife;
@Id
@GeneratedValue
public int getId() {
return id;
}
@OneToOne
//@JoinColumn(name="wifeId") //指定外键的名字为wifeId
@PrimaryKeyJoinColumn //用此注解表示主键关联
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
//一些属性的getter/setter方法 省略
}
一对一单向主键关联xml文件实现
在文档中,给出的方法截图如下:
将上述方法应用到我们的Student类和IdCard类中,如下:
Student类
public class Student {
private int id;
private String name;
//...get、set方法
}
IdCard类
public class IdCard {
private int id;
private String num;
private Student student;
//...get、set方法
}
IdCard.hbm.xml文件内容如下:
注意:此时的id生成策略。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="IdCard" table="idcard" >
<id name="id" column="id">
<generator class="foreign">
<param name="property">student</param>
</generator>
</id>
<property name="num" column="num"/>
<!-- -->
<one-to-one name="student" class="Student" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
Student.hbm.xml文件内容如下
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.model">
<class name="Student" table="student" >
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
测试结果如下:
关于主键关联这里就不再进行过多的介绍,这是由于在实际项目中,一对一关联关系并不太多,即使出现,我们一般也是采用一对一的外键进行关联。
由于使用Annotation比使用xml进行关联关系更容易理解和实现。因此,建议使用。