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
或 ArrayList
。
集
合类实例具有值类型的通常行为。当被持久化对象引用后,他们会自动被持久化,当不再被引用后,自动被删除。假若实例被从一个持久化对象传递到另一个,它的
元素可能从一个表转移到另一个表。两个实体不能共享同一个集合类实例的引用。因为底层关系数据库模型的原因,集合值属性无法支持空值语
义;Hibernate 对空的集合引用和空集合不加区别。
你不需要过多的为此担心。就如同你平时使用普通的 Java 集合类一样来使用持久化集合类。只是要确认你理解了双向关联的语义(后文将进行讨论)。