开发者创建属于他们自己的值类型也是很容易的。比如说,你可能希望持久化java.lang.BigInteger类型的属性,持久化成为VARCHAR字段。Hibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说,你可能有这样的Java属性:getName()/setName(),这是java.lang.String类型的,对应的持久化到三个字段:FIRST_NAME, INITIAL, SURNAME。
要实现一个自定义类型,可以实现net.sf.hibernate.UserType或net.sf.hibernate.CompositeUserType中的任一个,并且使用类型的Java全限定类名来声明属性。请查看net.sf.hibernate.test.DoubleStringType这个例子,看看它是怎么做的。
<property name="twoStrings" type="net.sf.hibernate.test.DoubleStringType">
<column name="first_string"/>
<column name="second_string"/>
</property>
注意使用<column>标签来把一个属性映射到多个字段的做法。
虽然Hibernate内置的丰富类型和对component的支持意味着你可能很少需要使用自定义类型,至少对于你程序中经常出现的自定义类(并非实体)来说,这是一种好方法。比如说,MonetoryAmount(价格总额)对比使用CompositeUserType来说更好,虽然它可以很容易的使用一个component实现。这样做的动机之一是抽象。通过自定义类型,以后假若你改变表示金额值的方法时,你的映射文件不需要更改,这就得到了保护。
这是属性映射的又一种类型。<any>映射元素定义了一种从多个表到类的多形联合。这种类型的映射总是需要多于一个字段。第一个字段持有被从属的实体的类型。其他的字段持有标识符。对于这种类型的联合来说,不可能指定一个外键约束,所以当然这不是(多形)联合映射的通常方式。你只应该在非常特殊的情况下使用它(比如,审计log,用户会话数据等等)。
<any name="anyEntity" id-type="long" meta-type="eg.custom.Class2TablenameType">
<column name="table_name"/>
<column name="id"/>
</any>
meta-type属性让应用程序指定一个自定义类型,把数据库字段值映射到一个持久化类,该类的标识属性是用id-type定义的。如果meta-type返回java.lang.Class的实例,不需要其他处理。另一方面,如果是类似string或者character这样的基本类型,你必须指定从值到类的映射。
<any name="anyEntity" id-type="long" meta-type="string">
<meta-value value="TBL_ANIMAL" class="Animal"/>
<meta-value value="TBL_HUMAN" class="Human"/>
<meta-value value="TBL_ALIEN" class="Alien"/>
<column name="table_name"/>
<column name="id"/>
</any>
<any
name="propertyName"
id-type="idtypename"
meta-type="metatypename"
cascade="none|all|save-update"
access="field|property|ClassName"
>
<meta-value ... />
<meta-value ... />
.....
<column .... />
<column .... />
.....
</any>
![]() |
name: 属性名。 |
![]() |
id-type: 标识符类型。 |
![]() |
meta-type (可选 - 默认为class): 一个用于把java.lang.Class映射到一个数据库字段的类或者允许分辨映射的类型。 |
![]() |
cascade(级联) (可选- 默认为 none): 级联风格。 |
![]() |
access (可选 - 默认是 property): Hibernate用来访问属性的策略。 |
老式的object 类型是用来在Hibernate 1.2中起到类似作用的,他仍然被支持,但是已经基本废弃了。
你可强制Hibernate在生成的SQL中把标识符用引号前后包围起来,这需要在映射文档中使用反向引号(`)把表名或者字段名包围(可能比较拗口,请看下面的例子)。Hibernate会使用相应的SQLDialect(方言)来使用正确的引号风格(通常是双引号,但是在SQL Server中是括号,MySQL中是反向引号)。
<class name="LineItem" table="`Line Item`">
<id name="id" column="`Item Id`"/><generator class="assigned"/></id>
<property name="itemNumber" column="`Item #`"/>
...
</class>
Hibernate映射文档也包含一些只为了SchemaExport命令行工具生成DDL使用的信息。比如,你可以使用<column>元素的sql-type属性覆盖字段类型。
<property
name="amount"
type="big_decimal">
<column
name="AMOUNT"
sql-type="NUMERIC(11, 2)"/>
</property>
或者,你可以指定字段长度和约束。下面是等价的:
<property
name="socialSecurityNumber"
type="string"
length="9"
column="SSN"
not-null="true"
unique="true"/>
<property
name="socialSecurityNumber"
type="string">
<column
name="SSN"
length="9"
not-null="true"
unique="true"/>
</property>
最后,也可以通过SchemaExport命令行工具自动生成所需的索引。如果要这么做,请在<column>元素上使用index属性。
<property
name="lastname">
<column
name="LASTNAME"
index="by_last_first"/>
</property>
<property
name="firstname">
<column
name="FIRSTNAME"
index="by_last_first"/>
</property>
关于SchemaExport的更多内容,请参见本文档的“工具箱”那一章。
允许在独立的映射文档中定义subclass和joined-subclass,直接位于hibernate-mapping下。这就可以让你每次扩展你的类层次的时候,加入新的映射文件就行了。在子类的映射中你必须指定一个extents属性,指明先前已经映射过的超类。使用这个功能的时候,一定要注意映射文件的排序是非常重要的!
<hibernate-mapping>
<subclass name="eg.subclass.DomesticCat" extends="eg.Cat" discriminator-value="D">
<property name="name" type="string"/>
</subclass>
</hibernate-mapping>