1.3.4. 值类型的集合

我们把一个值类型对象的集合加入Person实体中。我们希望保存email地址,所以使用String类型,而且这次的集合类型又是Set

  1. private Set emailAddresses = new HashSet();
  2. public Set getEmailAddresses() {
  3. return emailAddresses;
  4. }
  5. public void setEmailAddresses(Set emailAddresses) {
  6. this.emailAddresses = emailAddresses;
  7. }

这个Set的映射

  1. <set name="emailAddresses" table="PERSON_EMAIL_ADDR">
  2. <key column="PERSON_ID"/>
  3. <element type="string" column="EMAIL_ADDR"/>
  4. </set>

比较这次和此前映射的差别,主要在于element部分,这次并没有包含对其它实体引用的集合,而是元素类型为String的集合(在映射中使用小写的名字”string“是向你表明它是一个Hibernate的映射类型或者类型转换器)。和之前一样,set元素的table属性决定了用于集合的表名。key元素定义了在集合表中外键的字段名。element元素的column属性定义用于实际保存String值的字段名。

看一下修改后的数据库schema。

  1. _____________ __________________
  2. | | | | _____________
  3. | EVENTS | | PERSON_EVENT | | | ___________________
  4. |_____________| |__________________| | PERSON | | |
  5. | | | | |_____________| | PERSON_EMAIL_ADDR |
  6. | *EVENT_ID | <--> | *EVENT_ID | | | |___________________|
  7. | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID |
  8. | TITLE | |__________________| | AGE | | *EMAIL_ADDR |
  9. |_____________| | FIRSTNAME | |___________________|
  10. | LASTNAME |
  11. |_____________|

你可以看到集合表的主键实际上是个复合主键,同时使用了2个字段。这也暗示了对于同一个person不能有重复的email地址,这正是Java里面使用Set时候所需要的语义(Set里元素不能重复)。

你现在可以试着把元素加入到这个集合,就像我们在之前关联person和event的那样。其实现的Java代码是相同的:

  1. private void addEmailToPerson(Long personId, String emailAddress) {
  2. Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  3. session.beginTransaction();
  4. Person aPerson = (Person) session.load(Person.class, personId);
  5. // The getEmailAddresses() might trigger a lazy load of the collection
  6. aPerson.getEmailAddresses().add(emailAddress);
  7. session.getTransaction().commit();
  8. }

这次我们没有使用fetch查询来初始化集合。因此,调用其getter方法会触发另一附加的select来初始化集合,这样我们才能把元素添加进去。检查SQL log,试着通过预先抓取来优化它。