`

[转]hibernate随笔

阅读更多

对那些看重删除性能的系统,推荐所有的键都应该定义为on-delete=”cascade”,这样Hibernate将使用数据库级的on cascade delete约束,而不是多个delete语句。注意:这个特性会绕过Hibernate通常对版本数据(versioned data)采用的乐观锁策略。
not-null和update属性在映射单向一对多关联的时候有用。如果你映射一个单向一对多关联到非空的(non-nullable)外键,你必须用<key not-null=”true”>定义此键字段。

任何接受column属性的映射元素都可以选择接受<column>子元素。同样的,formula子元素也可以替换<formula>属性。

<any>映射元素定义了一种从多个表到类的多态关联。这种类型的映射常常需要多于一个字段。第一个字段持有被关联实体的类型,其他的字段持有标识符。只应该在非常特殊的情况下使用(比如,审计log,用户会话数据等等)。

要建立一个双向的多对多关联,只需要映射两个many-to-many关联到同一个数据库表中,并再定义其中的一端为inverse(使用哪一端要根据你的选择,便它不能是一个索引集合)。

要建立一个一对多的双向关系,你可以通过把一个一对多关联,作为一个多对一关联映射到同一张表的字段上,并且在“多”的那一端定义inverse=”truse”。

————————————————————
关联关系映射

在传统的数据建模中,允许为Null值的外键被认为是一种不好的实践,因此一般应该使用不允许为Null的外键。

单向many-to-one关联是最常见的单向关联关系。
基于外键关联的单向一对一关联和单向多对一关联几乎是一样的。惟一的不同就是单向一对一关联中的外键字段具有惟一性约束。如:
<class name=”Person”>
<id name=”id” column=”personId”>
    <generator class=”native”>
</id>
<many-to-one name=”address” column=”addressId” unique=”true” not-null=”true”/>
</class>

<class name=”Address”>
<id name=”id” column=”addressId”>
    <generator class=”native”/>
</id>
</class>

基于主键关联的单向一对一关联通常使用一个特定的id生成器。与上面的例子的区别是关联的方向。
<class name=”Person”>
<id name=”id” column=”personId”>
    <generator class=”native”>
</id>
</class>

<class name=”Address”>
<id name=”id” column=”personId”>
    <generator class=”foreign”>
      <param name=”property”>person</param>
    </generator>
</id>
<one-to-one name=”person” constrained=”true”>
</class>

基于外键关联的单向一对多关联是一种很少见的情况,并不推荐使用。对于这种关联关系最好使用连接表。

基于连接表的单向一对多关联应该优先被采用。通过指定unique=”true”,我们可以把多样性从多对多改变为一对多。

基于连接表的单向一对一关联非常少见。

双向多对一关联是最常见的关联关系。(这也是标准的父/子关联关系。)
如果使用List(或者其他有序集合类),需要设置外键对应的key列为not null,让hibernate来从集合端管理关联,维护每个元素的索引(通过设置update=”false” and insert=”false”来对另一端反向操作)。
假若集合映射的<key>元素对应的底层外键字段是NOT NULL的,那么为这一key元素定义not-null=”true”是很重要的。不要仅仅为可能的嵌套<column>元素定义not-null=”true”,<key>元素也是需要的。

基于外键关联的双向一对一关联也很常见。
基于主键关联的一对一关联需要使用特定的id生成器。

基于连接表的双向一对多关联。注意inverse=”true”可以出现在关联的任意一端,即collection端或者join端。
基于连接表的双向一对一关联极为罕见。

组件(Componet)是一个被包含的对象,在持久化的过程中,它被当作值类型,而并非一个实体的引用。
组件不支持共享引用。组件的值可以为空。每当Hibernate重新加载一个包含组件的对象,如果该组件的所有字段为空,Hibernate将假定整个组件为空。
组件的属性可以是任意一种Hibernate类型。
<componect>元素还允许有<parent>子元素,用来表明componect类的一个属性是指向包含它的实体的引用。

如果你定义的Set包含组合元素(composite-element),正确地实现equals()和hashCode()是非常重要的。
组合元素可以包含组件,但不能包含集合。

如果使用<set>标签,一个组合元素的映射不支持可能为空的属性。因此,要么在组合元素中使用不能为空的属性,要第选择使用<list>,<map>,<bag>或者<idbag>而不是<set>。组合元素有个特别的用法是它可以包含一个<many-to-one>元素。

组件类可以作为一个实体类的标识符,但必须满足:
1、必须实现java.io.Serializable接口。
2、
必须重新实现equals()和hashCode()方法,始终和组合关键字在数据库中的概念保持一致。

不能使用一个IdentifierGenerator产生组合关键字。一个应用程序必须分配它自己的标识符。

Hibernate collections被当作其所属实体而不是其包含实体的一个逻辑部分。它主要体现为以下几点:
1、当删除或增加collection中的对象的时候,collection所属者的版本值会递增。
2、如果一个从collection中移除的对像是一个值类型的实例,比如conposite element,那么这个对象的持久化状态就会终止,其在数据库中对应的记录会被删除。同样,向collection增加一个值类型的实例将会使之立即被持久化。
3、如果从一对多或者多对多关联的collection中移除一个实体,在缺少情况下这个对象并不会被删除。这个行为是完全符合逻辑的–改变一个实体的内部状态不应该使与它关联的实体消失掉。同样,向collection增加一个实体不会使之被持久化。
实际上,向collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已,同样移除的时候也只是删除连接。

对于one-to-many,如果将连接建在one这一端(如一个parent有多个child),则每次插入需要两条sql语句。正确的方式应该是将连接添加到many这一端(inverse=”true”)。
如:
Parent p = (Parent)session.load(Parent.class, pid);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c);
session.save(c);
session.flush();
为了更有条理,可以为Parent加一个addChild()方法。
public void addChild(Child c)
{
    c.setParent(this);
    children.add(c);
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics