对象和对象之间除了继承关系之外,还存在着关联关系:包括分作一对一、一对多、多对一和多对多,由于这几种关系在kodo ejb中的实现原理基本类似,因此本文中主要就一对一类关联关系进行深入的讲述,同时通过简单例子的分析和实践详细的说明如何使用kodo ejb中提供的注释来定义类和类之间的关联关系,剩下的一对多、多对一和多对多三种关系将只在文章最后进行说明,请读者参考一对一关系的实现过程。
面向对象的世界里,类a和类b之间的一对一关系必须满足如下条件:
在关系数据库中,我们通常使用唯一外键的方式来实现一对一关系,下面这个图说明了这种的情况。
下面开始介绍一下kodo ejb中和一对一关系实现相关的知识,为了说明的需要,我们首先定义一个虚拟的场景。
模拟场景
我们假定要完成一个图书馆管理系统,该系统中需要管理很多书,我们需要记录书的基本信息如编号、书名、出版日期等基本信息,还需要记录书的前言,序等信息。
假设我们根据上面的需求,将书设计成一个类(book),包括了书的编号和名称两个属性,同时将书的前言信息设计成另外一个类(bookextend),它包括了书的编号和前言信息两个属性。由于一本书有前言而且也不可能有其他的书前言部分会和他一样,所以类book和bookextend之间很自然的形成了一对一的关系。这两个类的属性以及类之间的关系如下图所示。
[注]
1、为了说明的简单,例子设计时每个对象仅仅选择了必要的属性。
2、上面的设计仅仅为了演示的要求而特意采用,不代表设计合理。
kodo ejb中和一对一关系实现相关的内容
在kodo ejb中,我们可以使用简单的onetoone注释来声明类和类之间的一对一关系,另外可选的,我们可以使用joincolumn注释来声明两个类对应的表之间使用什么字段来进行关联。
onetoone
onetoone注释提供了5个属性供开发者定义类和类之间一对一关系的细节内容。
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属性。
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; /** * book 用于表征系统中的书籍对象,他有三个属性
* id - 书籍编号,书籍编号将由mysql数据库自动生成
* name - 书名
* bookextend – 书的扩展信息,和bookextend是一对一(onetoone)关系 */ /* entity注释表示该类是持久化类,的name属性是该实体在查询中对应的唯一名称,默认是类名 */ @entity(name = "book") /* table注释的name属性指定该持久化类对应的数据表的名称,默认数据表名和类名保持一致,为了
* 增强代码的可移植性,建议大家在name属性中使用大写英文字母 */ /* inheritance注释的strategy确定了持久化对象和数据表之间的关系,可选择项包括single_table、joined和table_per_class,我们这里采用joined */ /* table_per_class : strategy 设置为该选项表示每个类使用一个表,也就是上面所说的第一种情况*/ /* single_table : strategy 设置为该选项表示所有类及其子类共用一个表,也就是上面所说的第二种情况*/ /* joined : strategy 设置为该选项表示每个类使用子表保存子类比父类多出的属性,也就是上面所说的第三种情况*/ @inheritance(strategy = inheritancetype.joined) public class book { /* id注释表示该字段是标识字段 */ @id /* generatedvalue注释定义了该标识字段的产生方式,我们的演示系统中id由mysql数据库字段自动生成,因此选择generationtype.identity */ @generatedvalue(strategy = generationtype.identity) /* column注释的name属性定义了该类属性对应的数据字段的名称,为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 */ @column(name = "id") public int id; /* basic注释表示该属性是基本属性 */ @basic /* column注释的name属性定义了该类属性对应的数据字段的名称,为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 */ @column(name = "name") public string name = null; /* 使用onetoone注释表示该属性和book类形成一对一关系,onetoone注释的option属性设为true表示该对象可以不存在,cascade属性设置为cascadetype.all,表示book和bookextend对象级联新建、更新、删除、刷新 */ @onetoone(optional=true,cascade=cascadetype.all) /* 使用joincolumn注释设置两个对象对应数据库表之间的关联字段 */ @joincolumn(name="extendid",referencedcolumnname="id") public bookextend bookextend; }
bookextend类
package org.vivianj.kodo.examples.beans; import javax.persistence.basic; 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; /** * bookextend 用于表征系统中书的扩展信息,他有两个属性:调用代码
* id - 扩展信息编号,扩展信息编号将由mysql数据库自动生成
* name - 书的前言信息
*/ /* entity注释表示该类是持久化类,的name属性是该实体在查询中对应的唯一名称,默认是类名 */ @entity /* table注释的name属性指定该持久化类对应的数据表的名称,默认数据表名和类名保持一致,为了
* 增强代码的可移植性,建议大家在name属性中使用大写英文字母 */ /* inheritance注释的strategy确定了持久化对象和数据表之间的关系,可选择项包括
* single_table、joined和table_per_class,我们这里采用joined */ /* table_per_class : strategy 设置为该选项表示每个类使用一个表,也就是上面所说的第一种情况*/ /* single_table : strategy 设置为该选项表示所有类及其子类共用一个表,也就是上面所说的第二种情况*/ /* joined : strategy 设置为该选项表示每个类使用子表保存子类比父类多出的属性,也就是上面所说的第三种情况*/ @inheritance(strategy = inheritancetype.joined) public class bookextend { /* id注释表示该字段是标识字段 */ @id /* generatedvalue注释定义了该标识字段的产生方式,我们的演示系统中id由mysql数据库字段自动生成,因此选择generationtype.identity */ @generatedvalue(strategy = generationtype.identity) /* column注释的name属性定义了该类属性对应的数据字段的名称,为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 */ @column(name = "id") public int id; /* basic注释表示该属性是基本属性 */ @basic /* column注释的name属性定义了该类属性对应的数据字段的名称,为了最大限度保持系统和数据库之前的独立性,建议使用大写字符 */ @column(name = "name") public string name = null; }
/* 获得ejb的实体管理器 */ entitymanagerfactory emf = persistence.createentitymanagerfactory(null); entitymanager em = emf .createentitymanager(persistencecontexttype.extended); /* 开始事务 */ em.gettransaction().begin(); /* 创建新的book对象 */ book book = new book(); /* 设置book对象的name属性 */ book.name = "kodo入门"; /* 创建新的bookextend对象 */ bookextend bookextend = new bookextend(); /* 设置对象属性 */ bookextend.name = "spring is a very good book that ..."; /* 建立对象之间的关系 */ book.bookextend = bookextend; /* 持久化对象,只需要持久化book对象,不需要单独持久化bookextend对象 */ em.persist(book); /* 结束事务 */ em.gettransaction().commit(); em.close(); emf.close();级联更新对象状态
/* 获得ejb的实体管理器 */ entitymanagerfactory emf = persistence.createentitymanagerfactory(null); entitymanager em = emf .createentitymanager(persistencecontexttype.extended); /* 开始事务 */ em.gettransaction().begin(); /* 创建新的book对象 */ book book = new book(); /* 设置book对象的id属性 */ book.id= 1; book.name = “kodo 入门”; /* 创建新的bookextend对象 */ bookextend bookextend = new bookextend(); /* 设置对象属性 */ bookextend.id=1; bookextend.name = "kodo 分为kodo ejb和kodo jdo ..."; /* 建立对象之间的关系 */ book.bookextend = bookextend; /* 持久化对象,只需要调用book对象的merge方法,不需要单独处理bookextend对象 */ em.merge(book); /* 结束事务 */ em.gettransaction().commit(); em.close(); emf.close();级联删除对象
/* 获得ejb的实体管理器 */ entitymanagerfactory emf = persistence.createentitymanagerfactory(null); entitymanager em = emf .createentitymanager(persistencecontexttype.extended); /* 开始事务 */ em.gettransaction().begin(); /* 使用查询删除对象,可以不必将对象加入到内存中,提高效率 */ query q = entitymanager .createquery("delete from book c where c.id=:id"); int id = book.id; /* 设置被删除book对象的主键值 */ q.setparameter("id", id); /* 当方法被调用时,book对象对应的bookextend对象会同时被删除 */ q.executeupdate(); /* 结束事务 */ em.gettransaction().commit(); em.close(); emf.close();其他几种关联关系
新闻热点
疑难解答