(译者注:在阅读本章的时候,以后整个手册的阅读过程中,我们都会面临一个名词方面的问题,那就是“集合”。"Collections"和"Set"在中文里对应都被翻译为“集合”,但是他们的含义很不一样。Collections是一个超集,Set是其中的一种。大部分情况下,本译稿中泛指的未加英文注明的“集合”,都应当理解为“Collections”。在有些二者同时出现,可能造成混淆的地方,我们用“集合类”来特指“Collecions”,“集合(Set)”来指"Set",一般都会在后面的括号中给出英文。希望大家在阅读时联系上下文理解,不要造成误解。 与此同时,“元素”一词对应的英文“element”,也有两个不同的含义。其一为集合的元素,是内存中的一个变量;另一含义则是XML文档中的一个标签所代表的元素。也请注意区别。 本章中,特别是后半部分是需要反复阅读才能理解清楚的。如果遇到任何疑问,请记住,英文版本的reference是惟一标准的参考资料。)
这部分不包含大量的Java代码例子。我们假定你已经了解如何使用Java自身的集合类框架(Java's collections framework)。 其实如果是这样, 这里就真的没有什么东西需要学习了... 用一句话来做个总结,你就用你已经掌握的知识来使用它们吧,不用为了适应Hibernate而作出改变.
Hibernate可以持久化以下java集合的实例, 包括java.util.Map, java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, 和任何持久实体或值的数组。类型为java.util.Collection或者java.util.List的属性还可以使用"bag"语义来持久。
警告:用于持久化的集合,除了集合接口外,不能保留任何实现这些接口的类所附加的语义(例如:LinkedHashSet带来的迭代顺序)。所有的持久化集合,实际上都各自按照 HashMap, HashSet, TreeMap, TreeSet 和 ArrayList 的语义直接工作。更深入地说,对于一个包含集合的属性来说,必须把Java类型定义为接口(也就是Map, Set 或者List等),而绝不能是HashMap, TreeSet 或者 ArrayList。存在这个限制的原因是,在你不知道的时候,Hibernate暗中把你的Map, Set 和 List 的实例替换成了它自己的关于Map, Set 或者 List 的实现。(所以在你的程序中,谨慎使用==操作符。)(译者说明: 为了提高性能等方面的原因,在Hibernate中实现了几乎所有的Java集合的接口 。)
Cat cat = new DomesticCat(); Cat kitten = new DomesticCat(); .... Set kittens = new HashSet(); kittens.add(kitten); cat.setKittens(kittens); session.save(cat); kittens = cat.getKittens(); //Okay, kittens collection is a Set (HashSet) cat.getKittens(); //Error!
集合遵从对值类型的通常规则:不能共享引用, 与其包含的实体共存亡。由于存在底层的关联模型,集合不支持空值语义;并且hibernate不会区分一个null的集合引用和一个不存在元素的空集合。
集合实例在数据库中根据指向对应实体的外键而得到区别。这个外键被称为集合的关键字。在Hibernate配置文件中使用<key> 元素来映射这个集合的关键字。
集合可以包含几乎所有的Hibernate类型, 包括所有的基本类型, 自定义类型,实体类型和组件。集合不能包含其他集合。这些被包含的元素的类型被称为集合元素类型。集合的元素在Hibernate中被映射为<element>, <composite-element>, <one-to-many>, <many-to-many> 或者 <many-to-any>。
除了Set和Bag之外的所有集合类型都有一个索引(index)字段,这个字段映射到一个数组或者List的索引或者Map的key。Map的索引的类型可以是任何基本类型, 实体类型或者甚至是一个组合类型(但不能是一个集合类型)。数组和list的索引肯定是整型,integer。在Hibernate配置文件中使用 <index>, <index-many-to-many>, <composite-index> 或者 <index-many-to-any>等元素来映射索引。
集合类可以产生相当多种类的映射,涵盖了很多通常的关系模型。我们建议你练习使用schema生成工具, 以便对如何把不同的映射定义转换为数据库表有一个感性认识。
在Hibernate配置文件中使用<set>, <list>, <map>, <bag>, <array> 和 <primitive-array>等元素来定义集合,而<map>是最典型的一个。
<map name="propertyName"table="table_name"
schema="schema_name"
lazy="true|false"
inverse="true|false"
cascade="all|none|save-update|delete|all-delete-orphan"
sort="unsorted|natural|comparatorClass"
order-by="column_name asc|desc"
where="arbitrary sql where condition"
outer-join="true|false|auto"
batch-size="N" (11) access="field|property|ClassName" (12) > <key .... /> <index .... /> <element .... /> </map>
![]() |
name 集合属性的名称 |
![]() |
table (可选——默认为属性的名称)这个集合表的名称(不能在一对多的关联关系中使用) |
![]() |
schema (可选) 表的schema的名称, 他将覆盖在根元素中定义的schema |
![]() |
lazy (可选——默认为false) lazy(可选--默认为false) 允许延迟加载(lazy initialization )(不能在数组中使用) |
![]() |
inverse (可选——默认为false) 标记这个集合作为双向关联关系中的方向一端。 |
![]() |
cascade (可选——默认为none) 让操作级联到子实体 |
![]() |
sort(可选)指定集合的排序顺序, 其可以为自然的(natural)或者给定一个用来比较的类。 |
![]() |
order-by (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序 |
![]() |
where (可选) 指定任意的SQL where条件, 该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用) |
![]() |
outer-join(可选)指定这个集合,只要可能,应该通过外连接(outer join)取得。在每一个SQL语句中, 只能有一个集合可以被通过外连接抓取(译者注: 这里提到的SQL语句是取得集合所属类的数据的Select语句) |
(11) | batch-size (可选, 默认为1) 指定通过延迟加载取得集合实例的批处理块大小("batch size")。 |
(12) | access(可选-默认为属性property):Hibernate取得属性值时使用的策略 |
建立列表(List)和数组(Array)需要一个单独表字段用来保存列表(List)或数组(Array)的索引(foo[i]中的i)。如果你的关系模型中没有一个索引字段, 例如:如果你处理的是老式的遗留数据, 你可以用无序的Set来替代。这会让那些以为List应该是访问无序集合的比较方便的方法的人感到气馁。Hibernate集合严格遵守Set,List和Map接口中包涵的自然语义。 List元素不能正确的自发对他们自己进行排序!
在另一方面, 那些准备使用List来模拟bag的语义的人有一个合法的委屈(a legitimate grievance)。bag是一个无序,没有索引的集合并且可能包含多个相同的元素。在Java集合框架中没有Bag接口(虽然你可以用List模拟它)。Hibernate允许你映射类型为List或者Collection的属性到<bag>元素。注意: Bag语义事实上并不是Collection规范(contract)的一部分并且事实上它和List规范中的语义是相矛盾的。
具有inverse="false"标记的大型Hibernate bag效率是相当低的,应该尽量避免。Hibernate无法创建,删除和更新它的单个记录, 因为他们没有关键字来识别单个记录。