您好,欢迎访问代理记账网站
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

hibernate中文网 第五章 集合类(Collections)映射 2021-05-25 ~

概述

(译者注:在阅读本章的时候,以后整个手册的阅读过程中,我们都会面临一个名词方面的问题,那就是“集合”。"Collections"和"Set"在中文里对应都被翻译为“集合”,但是他们的含义很不一样。Collections是一个超集,Set是其中的一种。大部分情况下,本译稿中泛指的未加英文注明的“集合”,都应当理解为“Collections”。在有些二者同时出现,可能造成混淆的地方,我们用“集合类”来特指“Collecions”,“集合(Set)”来指"Set",一般都会在后面的括号中给出英文。希望大家在阅读时联系上下文理解,不要造成误解。 与此同时,“元素”一词对应的英文“element”,也有两个不同的含义。其一为集合的元素,是内存中的一个变量;另一含义则是XML文档中的一个标签所代表的元素。也请注意区别。 本章中,特别是后半部分是需要反复阅读才能理解清楚的。如果遇到任何疑问,请记住,英文版本的reference是惟一标准的参考资料。)

Hibernate要求持久化集合值字段必须声明为接口,比如:

public class Product {
    private String serialNumber;
    private Set parts = new HashSet();
    
    public Set getParts() { return parts; }
    void setParts(Set parts) { this.parts = parts; }
    public String getSerialNumber() { return serialNumber; }
    void setSerialNumber(String sn) { serialNumber = sn; }
}

实际的接口可能是java.util.Set, java.util.Collection, java.util.List, java.util.Map, java.util.SortedSet, java.util.SortedMap 或者...任何你喜欢的类型!("任何你喜欢的类型" 代表你需要编写 org.hibernate.usertype.UserCollectionType的实现.)

注意我们是如何用一个HashSet实例来初始化实例变量的.这是用于初始化新创建(尚未持久化)的类实例中集合值属性的最佳方法。当你持久化这个实例时——比如通过调用persist()——Hibernate 会自动把HashSet替换为Hibernate自己的Set实现。观察下面的错误:

Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.persist(cat);
kittens = cat.getKittens(); //Okay, kittens collection is a Set
(HashSet) cat.getKittens(); //Error!

根据不同的接口类型,被Hibernate注射的持久化集合类的表现类似HashMap, HashSet, TreeMap, TreeSet or ArrayList。

集合类实例具有值类型的通常行为。当被持久化对象引用后,他们会自动被持久化,当不再被引用后,自动被删除。假若实例被从一个持久化对象传递到另一个,它的元素可能从一个表转移到另一个表。两个实体不能共享同一个集合类实例的引用。因为底层关系数据库模型的原因,集合值属性无法支持空值语义;Hibernate对空的集合引用和空集合不加区别。

你不需要过多的为此担心。就如同你平时使用普通的Java集合类一样来使用持久化集合类。只是要确认你理解了双向关联的语义(后文讨论)。

6.1. 持久化集合类(Persistent collections)

6.2. 集合映射( Collection mappings )

  • 6.2.1. 集合外键(Collection foreign keys)
  • 6.2.2. 集合元素(Collection elements)
  • 6.2.3. 索引集合类(Indexed collections)
  • 6.2.4. 值集合于多对多关联(Collections of values and many-to-many associations)
  • 6.2.5. 一对多关联(One-to-many Associations)

6.3. 高级集合映射(Advanced collection mappings)

  • 6.3.1. 有序集合(Sorted collections)
  • 6.3.2. 双向关联(Bidirectional associations)
  • 6.3.3. 双向关联,涉及有序集合类
  • 6.3.4. 三重关联(Ternary associations)
  • 6.3.5. 使用<idbag>

6.4. 集合例子(Collection example)

6.1. 持久化集合类(Persistent collections)

(译者注:在阅读本章的时候,以后整个手册的阅读过程中,我们都会面临一个名词方面的问题,那就是“集合”。"Collections"和"Set"在中文里对应都被翻译为“集合”,但是他们的含义很不一样。Collections是一个超集,Set是其中的一种。大部分情况下,本译稿中泛指的未加英文注明的“集合”,都应当理解为“Collections”。在有些二者同时出现,可能造成混淆的地方,我们用“集合类”来特指“Collecions”,“集合(Set)”来指"Set",一般都会在后面的括号中给出英文。希望大家在阅读时联系上下文理解,不要造成误解。 与此同时,“元素”一词对应的英文“element”,也有两个不同的含义。其一为集合的元素,是内存中的一个变量;另一含义则是XML文档中的一个标签所代表的元素。也请注意区别。 本章中,特别是后半部分是需要反复阅读才能理解清楚的。如果遇到任何疑问,请记住,英文版本的reference是惟一标准的参考资料。)

Hibernate要求持久化集合值字段必须声明为接口,比如:

public class Product {
    private String serialNumber;
    private Set parts = new HashSet();
    
    public Set getParts() { return parts; }
    void setParts(Set parts) { this.parts = parts; }
    public String getSerialNumber() { return serialNumber; }
    void setSerialNumber(String sn) { serialNumber = sn; }
}

实际的接口可能是java.util.Set, java.util.Collection, java.util.List, java.util.Map, java.util.SortedSet, java.util.SortedMap 或者...任何你喜欢的类型!("任何你喜欢的类型" 代表你需要编写 org.hibernate.usertype.UserCollectionType的实现.)

注意我们是如何用一个HashSet实例来初始化实例变量的.这是用于初始化新创建(尚未持久化)的类实例中集合值属性的最佳方法。当你持久化这个实例时——比如通过调用persist()——Hibernate 会自动把HashSet替换为Hibernate自己的Set实现。观察下面的错误:

Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.persist(cat);
kittens = cat.getKittens(); //Okay, kittens collection is a Set
(HashSet) cat.getKittens(); //Error!

根据不同的接口类型,被Hibernate注射的持久化集合类的表现类似HashMap, HashSet, TreeMap, TreeSet or ArrayList。

集合类实例具有值类型的通常行为。当被持久化对象引用后,他们会自动被持久化,当不再被引用后,自动被删除。假若实例被从一个持久化对象传递到另一个,它的元素可能从一个表转移到另一个表。两个实体不能共享同一个集合类实例的引用。因为底层关系数据库模型的原因,集合值属性无法支持空值语义;Hibernate对空的集合引用和空集合不加区别。

你不需要过多的为此担心。就如同你平时使用普通的Java集合类一样来使用持久化集合类。只是要确认你理解了双向关联的语义(后文讨论)。

6.2. 集合映射( Collection mappings )

概述

用于映射集合类的Hibernate映射元素取决于接口的类型。比如, <set> 元素用来映射Set类型的属性。

<class name="Product">
    <id name="serialNumber" column="productSerialNumber"/>
    <set name="parts">
        <key column="productSerialNumber" not-null="true"/>
        <one-to-many class="Part"/>
    </set>
</class>

除了<set>,还有<list>, <map>, <bag>, <array> 和 <primitive-array> 映射元素。<map>具有代表性:

<map
    name="propertyName"                                         (1)
    table="table_name"                                          (2)
    schema="schema_name"                                        (3)
    lazy="true|extra|false"                                     (4)
    inverse="true|false"                                        (5)
    cascade="all|none|save-update|delete|all-delete-orphan|delet(6)e-orphan"
    sort="unsorted|natural|comparatorClass"                     (7)
    order-by="column_name asc|desc"                             (8)
    where="arbitrary sql where condition"                       (9)
    fetch="join|select|subselect"                               (10)
    batch-size="N"                                              (11)
    access="field|property|ClassName"                           (12)
    optimistic-lock="true|false"                                (13)
    mutable="true|false"                                        (14)
    node="element-name|."
    embed-xml="true|false"
>

    <key .... />
    <map-key .... />
    <element .... />
</map>
(1)

name 集合属性的名称

(2)

table (可选——默认为属性的名称)这个集合表的名称(不能在一对多的关联关系中使用)

(3)

schema (可选) 表的schema的名称, 他将覆盖在根元素中定义的schema

(4)

lazy (可选--默认为true) 可以用来关闭延迟加载(false),指定一直使用预先抓取,或者打开"extra-lazy" 抓取,此时大多数操作不会初始化集合类(适用于非常大的集合)

(5)

inverse (可选——默认为false) 标记这个集合作为双向关联关系中的方向一端。

(6)

cascade (可选——默认为none) 让操作级联到子实体

(7)

sort(可选)指定集合的排序顺序, 其可以为自然的(natural)或者给定一个用来比较的类。

(8)

order-by (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序

(9)

where (可选) 指定任意的SQL where条件, 该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用)

(10)

fetch (可选, 默认为select) 用于在外连接抓取、通过后续select抓取和通过后续subselect抓取之间选择。

(11)

batch-size (可选, 默认为1) 指定通过延迟加载取得集合实例的批处理块大小("batch size")。

(12)

access(可选-默认为属性property):Hibernate取得集合属性值时使用的策略

(13)

乐观锁 (可选 - 默认为 true): 对集合的状态的改变会是否导致其所属的实体的版本增长。 (对一对多关联来说,关闭这个属性常常是有理的)

(14)

mutable(可变) (可选 - 默认为true): 若值为false,表明集合中的元素不会改变(在某些情况下可以进行一些小的性能优化)。

  • 6.2.5. 一对多关联(One-to-many Associations)
  • 6.2.4. 值集合于多对多关联(Collections of values and many-to-many associations)
  • 6.2.3. 索引集合类(Indexed collections)
  • 6.2.2. 集合元素(Collection elements)
  • 6.2.1. 集合外键(Collection foreign keys)

6.2.1. 集合外键(Collection foreign keys)

集合实例在数据库中依靠持有集合的实体的外键加以辨别。此外键作为集合关键字段(collection key column)(或多个字段)加以引用。集合关键字段通过<key> 元素映射。

在外键字段上可能具有非空约束。对于大多数集合来说,这是隐含的。对单向一对多关联来说,外键字段默认是可以为空的,因此你可能需要指明 not-null="true"。

<key column="productSerialNumber" not-null="true"/>

外键约束可以使用ON DELETE CASCADE。

<key column="productSerialNumber" on-delete="cascade"/>

对<key> 元素的完整定义,请参阅前面的章节。

6.2.2. 集合元素(Collection elements)

集合几乎可以包含任何其他的Hibernate类型,包括所有的基本类型、自定义类型、组件,当然还有对其他实体的引用。存在一个重要的区别:位于集合中的对象可能是根据“值”语义来操作(其声明周期完全依赖于集合持有者),或者它可能是指向另一个实体的引用,具有其自己的生命周期。在后者的情况下,被作为集合持有的状态考虑的,只有两个对象之间的“连接”。

被包容的类型被称为集合元素类型(collection element type)。集合元素通过<element>或<composite-element>映射,或在其是实体引用的时候,通过<one-to-many> 或<many-to-many>映射。前两种用于使用值语义映射元素,后两种用于映射实体关联。

6.2.3. 索引集合类(Indexed collections)

所有的集合映射,除了set和bag语义的以外,都需要指定一个集合表的索引字段(index column)——用于对应到数组索引,或者List的索引,或者Map的关键字。通过<map-key>,Map 的索引可以是任何基础类型;若通过<map-key-many-to-many>,它也可以是一个实体引用;若通过<composite-map-key>,它还可以是一个组合类型。数组或列表的索引必须是integer类型,并且使用 <list-index>元素定义映射。被映射的字段包含有顺序排列的整数(默认从0开始)。

<map-key 
        column="column_name"                (1)
        formula="any SQL expression"        (2)
        type="type_name"                    (3)
        node="@attribute-name"
        length="N"/>
(1)

column(可选):保存集合索引值的字段名。

(2)

formula (可选): 用于计算map关键字的SQL公式

(3)

type (必须):映射键(map key)的类型。

<map-key-many-to-many
        column="column_name"                (1)
        formula="any SQL expression"        (2)(3)
        class="ClassName"
/>
(1)

column(可选):集合索引值中外键字段的名称

(2)

formula (可选): 用于计算map关键字的外键的SQL公式

(3)

class (必需):映射的键(map key)使用的实体类。

假若你的表没有一个索引字段,当你仍然希望使用List作为属性类型,你应该把此属性映射为Hibernate <bag>。从数据库中获取的时候,bag不维护其顺序,但也可选择性的进行排序。

从集合类可以产生很大一部分映射,覆盖了很多常见的关系模型。我们建议你试验schema生成工具,来体会一下不同的映射声明是如何被翻译为数据库表的。

 

 

 

 


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进