|
对象和对象之间除了继承关系之外,还存在着关联关系:包括分作一对一、一对多、多对一和多对多,由于这几种关系在 Kodo EJB 中的实现原理基本类似,因此本文中主要就一对一类关联关系进行深入的讲述,同时通过简单例子的分析和实践详细的说明如何使用 Kodo EJB 中提供的注释来定义类和类之间的关联关系,剩下的一对多、多对一和多对多三种关系将只在文章最后进行说明,请读者参考一对一关系的实现过程。
面向对象的世界里,类 A 和类 B 之间的一对一关系必须满足如下条件:
• 对象 A1 引用了对象 B1
• 类 A 其他对象 An 不可能应用同样的对象 B1
在关系数据库中,我们通常使用唯一外键的方式来实现一对一关系,下面这个图说明了这种的情况。

下面开始介绍一下 Kodo EJB 中和一对一关系实现相关的知识,为了说明的需要,我们首先定义一个虚拟的场景。 模拟场景
我们假定要完成一个图书馆管理系统,该系统中需要管理很多书,我们需要记录书的基本信息如编号、书名、出版日期等基本信息,还需要记录书的前言,序等信息。
假设我们根据上面的需求,将书设计成一个类( Book ),包括了书的编号和名称两个属性,同时将书的前言信息设计成另外一个类( BookExtend ),它包括了书的编号和前言信息两个属性。由于一本书有前言而且也不可能有其他的书前言部分会和他一样,所以类 Book 和 BookExtend 之间很自然的形成了一对一的关系。这两个类的属性以及类之间的关系如下图所示。

[ 注 ] 1 、为了说明的简单,例子设计时每个对象仅仅选择了必要的属性。
2 、上面的设计仅仅为了演示的要求而特意采用,不代表设计合理。 Kodo EJB 中和一对一关系实现相关的内容
在 Kodo EJB 中,我们可以使用简单的 OneToOne 注释来声明类和类之间的一对一关系,另外可选的,我们可以使用 JoinColumn 注释来声明两个类对应的表之间使用什么字段来进行关联。 OneToOne
OneToOne 注释提供了 5 个属性供开发者定义类和类之间一对一关系的细节内容。
• targetEntity
Class 类型的属性。
定义关系类的类型,默认是该成员属性对应的类类型,所以通常不需要提供定义。
• mappedBy
String 类型的属性。
定义类之间的双向关系。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系,我们就需要使用这个属性进行定义,否则可能引起数据一致性的问题。比如上面的演示场景中,我们只是定义 Book 类有 BookExtend 属性,而 BookExtend 并没有 Book 属性,那么他们是单向关系,如何 BookExtend 中也定义了 Book 属性,那么 Book 和 BookExtend 之间就构成了双向关系。
• cascade
CascadeType[] 类型。
该属性定义类和类之间的级联关系。定义的级联关系将被容器视为对当前类对象及其关联类对象采取相同的操作,而且这种关系是递归调用的。举个例子: Book 和 BookExtend 有级联关系,那么删除 Book 时将同时删除它所对应的 BookExtend 对象。而如果 BookExtend 还和其他的对象之间有级联关系,那么这样的操作会一直递归执行下去。
cascade 的值只能从 CascadeType.PERSIST (级联新建)、 CascadeType.REMOVE (级联删除)、 CascadeType.REFRESH (级联刷新)、 CascadeType.MERGE (级联更新)中选择一个或多个。还有一个选择是使用 CascadeType.ALL ,表示选择全部四项。
• fatch
FetchType 类型的属性。
可选择项包括: FetchType.EAGER 和 FetchType.LAZY 。前者表示关系类在主类加载的时候同时加载,后者表示关系类在被访问时才加载。默认值是 FetchType.EAGER 。
• optional
boolean 类型的属性。
定义该关联类对是否必须存在。如果设置为 false ,那么该属性就不能设置为 null 。默认值是 true 。 OneToOne 用法举例
public class Book{
// 其他内容 …
@OneToOne(optional=true,cascade=CascadeType.ALL)
public BookExtend bookExtend;
} JoinColumn
JoinColumn 注释用于定义主类在数据库中对应的表通过什么字段和关系类的主键进行关联,这个注释是可选的,如果不提供该注释, Kodo 在使用 ” 对象名 _ID” 和关联表进行关联(简单情况下),比如演示场景中类 Book 的 bookExtend 没有使用 JoinColumn 注释进行声明,我们使用 Kodo EJB 提供的 Mapping Tool 工具生成表格的时候, Book 类对应的表 Book 中将自动加入列 bookExtend_ID ,它的类型将和 BookExtend 对应表的主键字段 id 类型保持一致。
JoinColumn 注释中有两个属性: name 和 referencedColumnName 属性。
• name
String 类型。
它用于指定主类对应的表中和关系类的主键进行关联的字段的名称,比如上例中,我们不希望使用默认的 bookExtend_ID 字段名进行关联,我们可以在 Book 类中使用 JoinColumn 注释 bookExtend 属性,设置 JoinColumn 注释为自己想要的名字比如 extendID 或者其他。
• referencedColumnName
String 类型。
指定关联表中与主表形成关联关系的字段名。主要用于设置区别于主键字段的情况。比如 BookExtend 表中默认使用 Id 进行关联,但现在需要使用其他字段进行关联,我们就可以提供该属性。 JoinColumn 用法举例
public class Book{
// 其他内容 …
@OneToOne(optional=true,cascade=CascadeType.ALL)
@JoinColumn(name="extendID",referencedColumnName="ID")
public BookExtend bookExtend;
} 编写符合要求的持久化类
现在我们开始根据上面章节中介绍的内容编写符合模拟场景中要求的 Book 类和 BookExtend 类,下面是作者编写的两个类的全部代码,代码中加入了比较多的注释方便大家理解。 Book 类
package org.vivianj.kodo.examples.beans;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
/**
|