hibernate Join-subclass

Join-subclass基础(用于两个表之间通过连接外键)

One-to-One(两表之间一一映射)

考虑这样一个继承关系mammal与cat,dog。对应的类如下

publicclassMammal{

privateintid;

privateStringname;

}

publicclassCatextendsMammal{

privateStringkind;

privateintscratchLevel;

}

publicclassDogextendsMammal{

privateStringvariety;

privateintbiteLevel;

}

由于我们采用不同的table来存储相应的类数据,所以在设计上要选择较比巧妙的方法,即在cat与dog对应的table中采用主键映射的方法。我们将mammal对应的table中的id作为cat与dog的外键,并且在cat与dog对应的table中只存储以下的字段信息:

createtablecat(

cat_idintprimarykeynotnull,

kindvarchar(10)notnull,

scratchlevelintnotnull

);

createtabledog(

dog_idintprimarykeynotnull,

varietyvarchar(15)notnull,

bitelevelintnotnull

);

发现了没?cat与dog从mammal中继承的name域在table中没有相应的字段来存储。由于采用了外键的映射,我们将id与name存入mammal的table中,这样可以节省存储空间,并且很容易进行查找。

那么,外键对应的hibernate描述符如何写呢?我们选用joined-subclass来实现。cat相应的描述如下

<joined-subclassname="inheritedmapping2.Cat"table="CAT">

<keycolumn="CAT_ID"/>

<propertyname="kind"type="string"column="KIND"/>

<propertyname="scratchLevel"type="int"column="SCRATCHLEVEL"/>

</joined-subclass>

该片断在Mammal.hbm.xml中。其实除了joined-subclass这个描述字符串以外,其他的都同一般的描述符的一样。通过key,我们将cattable的id与mammaltable的id相联系,这样就实现了cat的两个table分开存储。dog中的映射片断与cat相似,改改table与property的值就好了。

查询时,同上一篇一样

Listcats=session.find("fromCat");

将选出数据库中全部的cat对象,"fromMammal"将选出所有的对象。

思考:joined-subclass是基于外键连接实现继承关系。

5.1.10.多对一(many-to-one)

通过many-to-one元素,可以定义一种常见的与另一个持久化类的关联。这种关系模型是多对一关联。(实际上是一个对象引用。)

<many-to-one

name="propertyName"

column="column_name"

class="ClassName"

cascade="all|none|save-update|delete"

outer-join="true|false|auto"

update="true|false"

insert="true|false"

property-ref="propertyNameFromAssociatedClass"

access="field|property|ClassName"

/>

name:属性名。

column(可选):字段名。

class(可选-默认是通过反射得到属性类型):关联的类的名字。

cascade(级联)(可选):指明哪些操作会从父对象级联到关联的对象。

outer-join(外连接)(可选-默认为自动):当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

update,insert(可选-defaultstotrue)指定对应的字段是否在用于UPDATE和/或INSERT的SQL语句中包含。如果二者都是false,则这是一个纯粹的“外源性(derived)”关联,它的值是通过映射到同一个(或多个)字段的某些其他属性得到的,或者通过trigger(除法器),或者是其他程序。

property-ref:(可选)指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

access(可选-默认是property):Hibernate用来访问属性的策略。

cascade属性允许下列值:all,save-update,delete,none。设置除了none以外的其它值会传播特定的操作到关联的(子)对象中。参见后面的“LifecycleObjects(自动管理生命周期的对象)”。

outer-join参数允许下列三个不同值:

auto(默认)使用外连接抓取关联(对象),如果被关联的对象没有代理(proxy)

true一直使用外连接来抓取关联

false永远不使用外连接来抓取关联

一个典型的简单many-to-one声明例子:

<many-to-onename="product"class="Product"column="PRODUCT_ID"/>

property-ref属性只应该用来对付老旧的数据库系统,可能出现外键指向对方关联表的是个非主键字段(但是应该是一个惟一关键字)的情况。这是一种十分丑陋的关系模型。比如说,假设Product类有一个惟一的序列号,它并不是主键。(unique属性控制Hibernate通过SchemaExport工具生成DDL的过程。)

<propertyname="serialNumber"unique="true"type="string"column="SERIAL_NUMBER"/>

那么关于OrderItem的映射可能是:

<many-to-onename="product"property-ref="serialNumber"column="PRODUCT_SERIAL_NUMBER"/>

当然,我们决不鼓励这种用法。

5.1.11.一对一

持久化对象之间一对一的关联关系是通过one-to-one元素定义的。

<one-to-one

name="propertyName"

class="ClassName"

cascade="all|none|save-update|delete"

constrained="true|false"

outer-join="true|false|auto"

property-ref="propertyNameFromAssociatedClass"

access="field|property|ClassName"

/>

name:属性的名字。

class(可选-默认是通过反射得到的属性类型):被关联的类的名字。

cascade(级联)(可选)表明操作是否从父对象级联到被关联的对象。

constrained(约束)(可选)表明该类对应的表对应的数据库表,和被关联的对象所对应的数据库表之间,通过一个外键引用对主键进行约束。这个选项影响save()和delete()在级联执行时的先后顺序(也在schemaexporttool中被使用)。

outer-join(外连接)(可选-默认为自动):当设置hibernate.use_outer_join的时候,对这个关联允许外连接抓取。

property-ref:(可选)指定关联类的一个属性,这个属性将会和本外键相对应。如果没有指定,会使用对方关联类的主键。

access(可选-默认是property):Hibernate用来访问属性的策略。

有两种不同的一对一关联:

主键关联

惟一外键关联

主键关联不需要额外的表字段;两行是通过这种一对一关系相关联的,那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联,你必须确认它们被赋予同样的标识值!

比如说,对下面的Employee和Person进行主键一对一关联:

<one-to-onename="person"class="Person"/>

<one-to-onename="employee"class="Employee"constrained="true"/>

NowwemustensurethattheprimarykeysofrelatedrowsinthePERSONandEMPLOYEEtablesareequal.WeuseaspecialHibernateidentifiergenerationstrategycalledforeign:现在我们必须确保PERSON和EMPLOYEE中相关的字段是相等的。我们使用一个特别的称为foreign的Hibernate标识符生成器策略:

<classname="person"table="PERSON">

<idname="id"column="PERSON_ID">

<generatorclass="foreign">

<paramname="property">employee</param>

</generator>

</id>

...

<one-to-onename="employee"

class="Employee"

constrained="true"/>

</class>

一个刚刚保存的Person实例被赋予和该Person的employee属性所指向的Employee实例同样的关键字值。

另一种方式是一个外键和一个惟一关键字对应,上面的Employee和Person的例子,如果使这种关联方式,应该表达成:

<many-to-onename="person"class="Person"column="PERSON_ID"unique="true"/>

如果在Person的映射加入下面几句,这种关联就是双向的:

<one-to-onename"employee"class="Employee"property-ref="person"/>

5.1.12.组件(component),动态组件(dynamic-component)

<component>元素把子对象的一些元素与父类对应的表的一些字段映射起来。然后组件可以声明它们自己的属性、组件或者集合。参见后面的“Components”一章。

<component

name="propertyName"

class="className"

insert="true|false"

upate="true|false"

access="field|property|ClassName">

<property...../>

<many-to-one..../>

........

</component>

name:属性名

class(可选-默认为通过反射得到的属性类型):组件(子)类的名字。

insert:被映射的字段是否出现在SQL的INSERT语句中?

update:被映射的字段是否出现在SQL的UPDATE语句中?

access(可选-默认是property):Hibernate用来访问属性的策略。

其<property>子标签为子类的一些属性和表字段建立映射。

<component>元素允许加入一个<parent>子元素,在组件类内部就可以有一个指向其容器的实体的反向引用。

<dynamic-component>元素允许把一个Map映射为组件,其属性名对应map的键值。

5.1.13.子类(subclass)

最后,多态持久化需要为父类的每个子类都进行声明。对于我们建议的“每一棵类继承树对应一个表”的策略来说,就需要使用<subclass>声明。

<subclass

name="ClassName"

discriminator-value="discriminator_value"

proxy="ProxyInterface"

lazy="true|false"

dynamic-update="true|false"

dynamic-insert="true|false">

<property..../>

.....

</subclass>

name:子类的全限定名。

discriminator-value(辨别标志)(可选-默认为类名):一个用于区分每个独立的子类的值。

proxy(代理)(可选):指定一个类或者接口,在延迟装载时作为代理使用。

lazy(延迟装载)(可选):设置lazy="true"是把自己的名字作为proxy接口的一种等价快捷方式。

每个子类都应该声明它自己的持久化属性和子类。<version>和<id>属性可以从根父类继承下来。在一棵继承树上的每个子类都必须声明一个唯一的discriminator-value。如果没有指定,就会使用Java类的全限定名。

5.1.14.连接的子类(joined-subclass)

另外一种情况,如果子类是持久化到一个属于它自己的表(每一个子类对应一个表的映射策略),那么就需要使用<joined-subclass>元素。

<joined-subclass

name="ClassName"

proxy="ProxyInterface"

lazy="true|false"

dynamic-update="true|false"

dynamic-insert="true|false">

<key....>

<property..../>

.....

</subclass>

name:子类的全限定名。

proxy(可选):指定一个类或者接口,在延迟装载时作为代理使用。

lazy(延迟装载)(可选):设置lazy="true"是把自己的名字作为proxy接口的一种等价快捷方式。

这种映射策略不需要指定辨别标志(discriminator)字段。但是,每一个都必须使用<key>元素指定一个表字段包含对象的标识符。本章开始的映射可以被用如下方式重写:

<?xmlversion="1.0"?>

<!DOCTYPEhibernate-mappingPUBLIC

"-//Hibernate/HibernateMappingDTD//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mappingpackage="eg">

<classname="Cat"table="CATS">

<idname="id"column="uid"type="long">

<generatorclass="hilo"/>

</id>

<propertyname="birthdate"type="date"/>

<propertyname="color"not-null="true"/>

<propertyname="sex"not-null="true"/>

<propertyname="weight"/>

<many-to-onename="mate"/>

<setname="kittens">

<keycolumn="MOTHER"/>

<one-to-manyclass="Cat"/>

</set>

<joined-subclassname="DomesticCat"table="DOMESTIC_CATS">

<keycolumn="CAT"/>

<propertyname="name"type="string"/>

</joined-subclass>

</class>

<classname="eg.Dog">

<!--mappingforDogcouldgohere-->

</class>

</hibernate-mapping>

5.1.15.map,set,list,bag

集合类在后面讨论。

5.1.16.引用(import)

假设你的应用程序有两个同样名字的持久化类,但是你不想在Hibernate查询中使用他们的全限定名。除了依赖auto-import="true"以外,类也可以被显式地“import(引用)”。你甚至可以引用没有明确被映射的类和接口。

<importclass="java.lang.Object"rename="Universe"/>

<import

class="ClassName"

rename="ShortName"

/>

class:任何Java类的全限定名。

rename(可选-默认为类的全限定名):在查询语句中可以使用的名字。

相关推荐