索引
1. JDO映射概述
我们在本前文中对Castor XML映射进行了详细的描述,并对Castor JDO做了一个概括介绍。Castor JDO在为XML文档与Java对象之间建立映射的同时,也提供了Java对象与关系数据库之间的映射机制,通常称为O/R映射。Castor映射文件可以同时为XML文档与Java对象,数据库关系表与Java对象之间提供映射信息。本文将对Castor O/R映射定义给出详细的描述。
下面是Castor O/R映射定义的例子:
<
mapping
xmlns
="
http://castor.exolab.org/
">
<
description
>
Castor generated mapping file
</
description
>
<
class
name
="
ZB_JG_SJB
"
identity
="
NUM_ID
">
<
description
>
Default mapping for class ZB_JG_SJB
</
description
>
<
map-to
table
="
ZB_JG_SJB
"/>
<
field
name
="
NUM_ID
"
type
="
int
"
required
="
true
">
<
sql
name
="
NUM_ID
"
type
="
decimal
"
dirty
="
check
"/>
</
field
>
<
field
name
="
time
"
type
="
java.util.Date
"
required
="
true
">
<
sql
name
="
time
"
type
="
timestamp
"
dirty
="
check
"/>
</
field
>
<
field
name
="
unirow
"
type
="
java.lang.String
"
required
="
true
">
<
sql
name
="
unirow
"
type
="
varchar
"
dirty
="
check
"/>
</
field
>
<
field
name
="
status
"
type
="
java.lang.String
"
required
="
true
">
<
sql
name
="
status
"
type
="
varchar
"
dirty
="
check
"/>
</
field
>
<
field
name
="
insert_Date
"
type
="
java.util.Date
"
required
="
true
">
<
sql
name
="
insert_Date
"
type
="
timestamp
"
dirty
="
check
"/>
</
field
>
</
class
>
</mapping> |
|
与Castor XML映射定义类似,一个Java类(<class>节点)通过<map-to>节点的“table”属性映射为一张数据库表(上例为
<
map-to
table
="
ZB_JG_SJB
"/>)。Java类字段(<field>节点)映射为数据库表中的列(通过<sql>节点表示)。
本文将不给出Mapping映射文件中各节点的Schema定义,关于其定义参考前文或Castor映射定义Schema文档。
2. 映射定义详解
2.1Mapping文件的根节点
如上例Mapping
文件所示,Mapping
文件的根节点为
<mapping>。<mapping>节点下的节点包括:
ü一个
<
description
>
节点,可选的,用于添加描述信息
ü一个或多个
<
include
>
节点,用于引用其他的映射文件
ü一个或多个
<
class
>
节点,用于描述每一个定义
Mapping
的
Java
类
ü一个或多个
<
key-generator
>
节点,该节点在
Castor JDO
中用于自动生成记录的主键。我们将在下文中对其做详细解释。
<
class
>
节点包含了
Java
类与数据库关系表之间映射的所有信息。该节点及其子节点详细描述了
Java
类中各个字段属性与数据库表列信息的映射关系。
Øname:
映射的Java
类名称,使用类的全名,如”com.acme.MyClass”
。
Øextends:
只有在该类扩展其他类时,使用该参数指定扩展的类。如果被扩展的类未在该Mapping
文件中指定,则不能使用该属性。
Ødepends:
在Castor JDO
中指明类之间的依赖关系,用于表示数据库表中关联表的概念。关于关联关系参考下一节
关联关系
。
Øauto-complete:
如果该属性值为”true”
,则Castor
在处理该类时首先采用自省的方式决定该类的字段属性,然后使用Mapping
文件中对该字段属性的设定覆盖自省方式的操作。auto-complete
属性可以让Castor
的默认自省处理方式与Mapping
定义方式很好的结合,从而降低对包含很多字段的类进行复杂的设定操作。
Øidentity:
在Castor JDO
中使用,用于描述该类实例的主键字段,详细信息参考Castor JDO
部分。
Øaccess:
在Castor JDO
中使用,详细信息参考Castor JDO
部分。
Økey-generator:
在Castor JDO
中使用,详细信息参考Castor JDO
部分。
Ødescription
:可选的属性,用于对该类添加描述性信息
Øcache-type:
只在Castor JDO
中使用,详细信息参考Castor JDO
部分。
Ømap-to:
可选属性,如果XML
中节点名称与类(Class)
名称不同,则使用该节点设定。默认的,Castor
会自动分析XML
节点名称和类名称之间的映射,如对于Java
类”XxxYyy”
,Castor
会自动映射为XML
节点”xxx-yyy”
。如果用户不希望Castor
自动生成该名称,则可以使用<map-to>
节点来指定XML
映射名称。注意:<map-to>
仅用于XML文档中的根节点。
Øfield
:节点下包含 零个或多个<field>节点。每个<field>节点用于描述Java类中的一个字段属性。<class>
<class>
映射举例
package mypackage public class MyClass { public int foo; public String getBar() { ... } public void setBar(String bar) { ... } } |
|
TestData
表结构如下
:
CREATE TABLE TestData ( ‘ID’ int(10) unsigned NOT NULL default '0', ‘Bar’ varchar(45) default NULL, ); |
|
用户需要以如下方式设定
Mapping
映射文件:
<mapping> ... <class name="mypackage.MyClass"> <map-to table="TestData"/> <field name="foo" type=”int” direct="true" ...> <sql name="ID" type="int"/> </field> </field name="bar" type=”string”> <sql name="Bar" type="char"/> </field> </class> ... </mapping> |
|
<map-to>
节点用于指定给定Java
类与数据库表名称的映射。
Øtable
属性:该Java
类所映射的关系数据库表的名称。
<field>
节点用于描述如何编组/
解编Java
对象中的字段属性。Castor
可以从<field>
节点描述中的”name”
属性确定Java
字段的名称;可以从<field>
节点描述中的”type”
和”collection”
属性确定Java
字段的类型;可以从<field>
节点描述中的”direct”
,”get-method”
和”set-method”
属性确定Java
字段的访问方法。通过上述信息,Castor
能够操作Java
类中的字段属性。
Castor
通过以下两个规则来判定某一字段的类型签名:
u检查
<field>节点中的“类型”属性(”type”和”collection”)
如果
<field>
节点中没有
”collection”
属性,
”type”
属性指定的类型即为该字段的
Java
类型。
”type”
属性值既可以是
Java
对象类型的全限定名
(
包含包名称
)
,也可以是
Castor
定义的一系列简称。
Castor
支持的类型别名及对应的原始
Java
类型列表如下:
简称
|
原始类型
|
Java类型
|
big-decimal
|
N
|
java.math.BigDecimal
|
big-integer
|
Y
|
java.math.BigInteger
|
boolean
|
Y
|
java.lang.Boolean.TYPE
|
byte
|
Y
|
java.lang.Byte.TYPE
|
bytes
|
N
|
byte[]
|
char
|
Y
|
java.lang.Character.TYPE
|
chars
|
N
|
char[]
|
clob
|
N
|
java.sql.Clob
|
date
|
N
|
java.util.Date
|
double
|
Y
|
java.lang.Double.TYPE
|
float
|
Y
|
java.lang.Float.TYPE
|
int
|
Y
|
java.lang.Integer.TYPE
|
integer
|
Y
|
java.lang.Integer
|
locale
|
N
|
java.util.Locale
|
long
|
Y
|
java.lang.Long.TYPE
|
other
|
N
|
java.lang.Object
|
serializable
|
Y
|
java.io.Serializable
|
short
|
Y
|
java.lang.Short.TYPE
|
sqldate
|
Y
|
java.sql.Date
|
sqltime
|
Y
|
java.sql.Date
|
string
|
N
|
java.lang.String
|
strings
|
N
|
String[]
|
stream
|
N
|
java.io.InputStream
|
timestamp
|
N
|
java.sql.Timestamp
|
Castor
会自动将数据库表中的数据转换为上述Java
对象类型。如果设定了”collection”属性,collection属性值遵从下面的对象对象列表:
简称
|
原始类型
|
Java
类型
|
array
|
<type_attribute>[]
|
<type_attribute>[]
|
enumerate
|
java.util.Enumeration
|
-
|
collection
|
java.util.Collection
|
java.util.ArrayList
|
set
|
java.util.Set
|
java.util.HashSet
|
arraylist
|
java.util.ArrayList
|
java.util.ArrayList
|
vector
|
java.util.Vector
|
java.util.Vector
|
map
|
java.util.Map
|
java.util.HashMap
|
hashtable
|
java.util.Hashtable
|
java.util.Hashtable
|
sortedset
|
java.util.SortedSet
|
java.util.TreeSet
|
iterator
|
java.util.Iterator
|
n/a
|
Collection集合中的对象为Java类型。对于Hashtable和Map类型的对象,Castor同时存储其键和值。对于其映射,可以使用org.exolab.castor.mapping.MapItem类通过顶层(相对于嵌套类映射)类映射定义和嵌套类映射定义来描述。
u
检查<field>
节点中的“签名”属性(”direct”,”set-method”
和”get-method”
)
如果
”direct”
属性设定为true,则在Java类定义中,该字段必须具有如下的声明:
public <type> <name>;
如果
”direct”
属性
设定为
false
或者该属性被忽略,
Castor
会通过该属性的存取方法访问该属性。首先,若设定了
'get-method'
或
'set-method'
,
Castor
会访问如下方法签名:
public <type> <get-method>();
或
public void <set-method>(<type> value);
若没有设定'get-method' 或'set-method'属性,Castor会尝试访问如下签名方法:
public <type> get<capitalized-name>();
或
public void set<capitalized-name>(<type> value);
<capitalized-name>是指Castor检查<name>属性值,将其首字母转换为大写,其他字符保持不变。
<field>节点可以包含将Java字段映射为XML元素,数据库表列名称等信息。<field>节点可配置的属性如下:
Ø
name: 该属性是必须的,即使在该映射类中没有该字段属性。如果配置了”direct”属性,”name”属性值必须是映射对象中的一个public字段(该字段必须是public,非static和非transient的类型)。如果没有”direct”和”get-/set-method”属性设定,“name”属性值对应的字段通过该值确定其访问方法(采用Java Bean规范)。
Ø
type: 该字段属性的Java类型。Castor使用该信息将XML信息转换为Java对象信息(如将字符串转换为整型),定义该字段访问方法的签名。如果设定了”collection”属性,该属性信息用于指定集合中对象的类型信息。
Ø
required: 在编组和解编过程中,该字段是否可选,默认值为false。
Ø
transient: 如果设定为”true”,该字段在处理过程中将被忽略。
Ø
direct: 如果为true,该字段在Java类定义中必须是public类型。
Ø
collection: 如果该字段存在多个,则Castor使用该属性的设定来处理他们。该类型用于定义对应Java类中集合的类型。
Ø
get-method: 可选配置,”name”属性对应Java类字段的访问方法,具体使用参考前文描述。
Ø
set-method: 可选配置,”name”属性对应Java类字段的访问方法,具体使用参考前文描述。
Ø
create-method: 工厂方法,用于构建FieldHandler实例。
在O/R Mapping中,<field>节点的子节点包含一个<sql>节点,用于描述如何将该字段属性映射的数据库表列信息。
<sql>
节点的用于描述Java
字段映射的数据库表列的详细信息。<sql>
节点的Schema
定义如下:
<
xsd:element
name
="
sql
">
<
xsd:complexType
>
<
xsd:attribute
name
="
name
"
type
="
xsd:NMTOKENS
"
use
="
optional
"/>
<
xsd:attribute
name
="
type
"
type
="
xsd:string
"
use
="
optional
"/>
<
xsd:attribute
name
="
many-table
"
type
="
xsd:NMTOKEN
"
use
="
optional
"/>
<
xsd:attribute
name
="
many-key
"
type
="
xsd:NMTOKENS
"
use
="
optional
"/>
<
xsd:attribute
name
="
read-only
"
type
="
xsd:boolean
"
use
="
optional
"
default
="
false
"/>
<
xsd:attribute
name
="
transient
"
type
="
xsd:boolean
"
use
="
optional
"/>
<
xsd:attribute
name
="
dirty
"
use
="
optional
"
default
="
check
">
<
xsd:simpleType
>
<
xsd:restriction
base
="
xsd:string
">
<
xsd:enumeration
value
="
check
"/>
<
xsd:enumeration
value
="
ignore
"/>
</
xsd:restriction
>
</
xsd:simpleType
>
</
xsd:attribute
>
</
xsd:complexType
>
</
xsd:element
>
Ø
name: 数据库表列名称。
Ø
type: 对应数据库列的JDBC类型。Castor支持的JDBC类型及其别名列表如下,在数据处理过程中,Castor会自动在SQL类型和Java类型间进行转换:
SQL Type
|
Java Type
|
bigint
|
java.lang.Long
|
binary
|
byte[]
|
bit
|
java.lang.Boolean
|
blob
|
java.io.InputStream
|
char
|
java.lang.String
|
clob
|
java.sql.Clob
|
decimal
|
java.math.BigDecimal
|
double
|
java.lang.Double
|
float
|
java.lang.Double
|
integer
|
java.lang.Integer
|
longvarbinary
|
byte[]
|
longvarchar
|
java.lang.String
|
numeric
|
java.math.BigDecimal
|
real
|
java.lang.Float
|
smallint
|
java.lang.Short
|
time
|
java.sql.Time
|
timestamp
|
java.sql.Timestamp
|
tinyint
|
java.lang.Byte
|
varbinary
|
byte[]
|
varchar
|
java.lang.String
|
|
Ø
read-only: 如果值为true,则数据库关系表中的该列将以只读方式操作。不会对其进行更新或删除操作。
Ø
transient: 如果该属性值为true,JDO在数据库序列化操作时忽略该字段。如果用户希望在Castor XML编组解编过程中同时忽略该节点,可以通过设定<field>节点的“transient”属性。
Ø
dirty:如果该属性值为“ignore”,则JDO在处理该字段的过程中将不检查数据库是否对该字段做了变更。
Ø
many-key: 【用于一对多和多对多关系】指定该节点对应的<field>节点所表示的对象所映射的数据库表中外键的列名称。
Ø
many-table: 【用于多对多关系】指定多对多关系中的关联中间表的名称。该关联中间表将关联双方联系起来。
说明:关于many-key及many-table属性参考下一节关联关系。
3. 关联关系
3.1关联关系概述
在Castor
中,对象之间的关联和依赖被区分为两种不同的关系。对于具有两种不同关系的多个对象,Castor
对这些对象的生命周期的维护是不同的。当两个对象为关联关系时,这两个对象必须各自进行创建(create
),删除(remove
)和更新(update
)。
在依赖关系中,一个对象必须在映射定义文件中显式的定义其Java
类“depends
”另一个Java
类。在映射定义文件中未声明依赖(depends
)其他类的Java
类称为主对象类,在数据库中往往称之为主表。依赖于主类的其他对象类称之为依赖对象类或从表。在Castor
映射定义文件中,一个依赖对象类只能依赖于一个主类。
如果一个对象类依赖于其他类,在该类对象在Castor
中不能独立的创建,删除和更新。Castor
在事务操作过程中,不允许一个依赖对象实例变更其主对象实例。依赖对象和主对象必须都要有主键,要么不使用key-generator
,要么都使用key-generator
。
下述例子表明,对象类com.xyz.MyDependentObject
是一个依赖对象类,com.xyz.MyObject
是一个主对象类。MyDependentObject
依赖于MyObject
。
<mapping> <class name="com.xyz.MyDependentObject" depends="com.xyz.MyObject"> ... </class> </mapping> |
|
3.2关联关系的处理
Castor
支持一对一,一对多和多对多的关联关系。多对多的关联关系中,由于每一个依赖对象只能有一个主对象,所以对象之间必须是关联(related
)的而不是依赖(depends
)的。
多对多关联关系中,必须有一个独立的表C
用于存储两个关联表A
和B
之间的关联信息。映射定义文件中<sql>
节点提供“many-key
”和“many-table
”两个属性表示这种关系。在多对多关系中,many-table
属性必须设定表C
;如果表A
中的主键名称不同于表C
中的外键的名称,则使用many-key
属性指定表C
中的外键的名称;如果表B
中的主键的名称不同于表C
中的外键的名称,则使用name
属性指定表C
中外键的名称。
下面以三个数据库表为例说明多对多关系的映射设定:
employee_table
|
id
|
name
|
salary
|
1482
|
Smith, Bob
|
$123,456
|
628
|
Lee, John
|
$43,210
|
1926
|
Arnold, Pascal
|
$24,680
|
department_table
|
id
|
name
|
comment
|
3
|
Accounting
|
|
7
|
Engineering
|
The very important department. :-)
|
employee_department
|
e_id
|
d_id
|
…
|
…
|
上述表中,employee
数据对象的映射关系举例如下:
<mapping> <class name="com.xyz.Employee" identity="id"> <map-to table="employee_table"/> <field name="id" type="integer"> <sql name="id"/> </field> <field> <sql many-table="employee_department" many-key="e_id" name="d_id"/> </field> <field name="salary"> <sql name="salary" type="integer"> </field> </class> </mapping> |
|
4. 延迟加载
Castor
支持在一对一,一对多及多对多的关联关系中使用延迟加载。使用延迟加载时,需要设定映射定义文件中<field>
的“lazy
”属性值为true
。
<mapping> <class name="com.xzy.Department"> ... <field "employee" type="com.xyz.Employee" lazy="true" /> ... </class> </mapping> |
|
如上所示,在一对一的关联关系中,当Castor
加载Department
对象时,将不会同时加载其引用的Employee
对象。只有使用Dempartment.getEmployee()
访问Employee
对象实例时,Castor
才会将Employee
对象数据从数据库加载到内存对象中。如果Employee
对象从未被访问过,则Castor
将永远不会加载该对象。
在一对多和多对多的关系中,如下所示:
<mapping> <class name="com.xzy.Department"> ... <field name="employee" type="com.xyz.Employee" lazy="true" collection="collection"/> </class> </mapping> |
|
在集合中的Employee
对象只有在应用访问该集合中的对象时(如使用集合的iterator()
方法),Castor
才会加载该集合内的数据
5. 联合主键
Castor支持联合主键的设定。如果数据库表使用多列唯一标识一条记录,则可以在数据映射定义文件中设定多个主键。如果下面的映射定义文件所示:
<mapping> <class name="com.xyz.MyObject" identity="firstName lastName"> <field name="firstName" type="string"> <sql name="fname"/> </field> <field name="lastName" type="string"> <sql name="lname"/> </field> ... </class> </mapping> |
|
多个主键在
<class>
节点的“
identity
”属性中以空格分隔。联合主键可以在主对象类,依赖对象类,各种关联关系(一对一,一对多和多对多)及延迟加载中使用。