藏品一览

好了,您已经了解了如何映射简单类型。现在是时候转向更有趣的问题了——如何映射对象集合。

我们可以将对象分为 5 组:

  • Array - 对象数组
  • 列表- 对象列表
  • Set - 一组对象
  • 地图- 对象字典
  • 集合——对象的集合

以及一个带有集合字段的类的示例:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @magical-annotation
   public List messages;
}

那么这个能让我们存储的不是一个字段而是多个值的神奇注解是什么?

此注释称为@ElementCollection。例子:

@Entity
@Table(name="user")
class User  {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   public List<String> messages;
}

它写得非常简单,但它的工作并不平凡。

辅助表

Entity 类的所有包含许多元素并用@ElementCollection注解标记的字段都包含在数据库中的一个特殊的辅助表中。事实上,这是合乎逻辑的。

该表可以包含两种形式的数据:

  • Ordered (List, Map) 包含三列:
    • 键列(外键)——对父对象 ID 的引用。
    • 索引列- 集合中的位置/索引。
    • 元素列- 值。
  • 无序(Set)包含两列:
    • 键列(外键)——对父对象 ID 的引用。
    • 元素列- 值。

您还可以使用注释显式设置此表的名称:

@CollectionTable(name="table_name")

例子:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message")
   public List<String> messages;
}

重要的!如果没有指定@CollectionTable注解,那么H​​ibernate会根据类名和字段名自己构建表名:User和字段讯息将表命名为“User_messages”。

收藏 收藏

但是我们不要把辅助表的创建交给Hibernate,我们自己创建。首先我们需要创建一个包含两列的表:

CREATE TABLE user_message {
    user_id INT,
    message VARCHAR(255)
};

请注意,此表没有自己的 ID 列。这是辅助表的主要特点。稍后您将熟悉其他类型的辅助表。

现在我们需要将这张表映射到我们的字段讯息用户类中。这看起来像这样:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message", joinColumns = @JoinColumn(name = "user_id"))
   @Column(name = "message")
   public Set<String> messages;
}

这里有两件事值得关注。

首先,用@Column (name = "message")注释指定的消息列位于user_message 辅助表中,而不是用户表中。

其次,在@JoinColumn(name = "user_id")注解中,我们指定了user_id列的名称,它指的是user表的id。这是为了让 Hibernate 知道如何正确地组合它们。

收藏

如果要将列表或数组的有序元素存储在辅助表中,则需要一个包含三列的表:

CREATE TABLE user_message {
    user_id INT,
    index INT,
    message VARCHAR(255)
};

如果你不喜欢“index”这个列名,或者你不能改变它,你可以在映射时指定一个不同的名字。为此,您需要使用@Index注释。

例子:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message",
       	indexes = { @Index(columnList = "list_index") }
       	joinColumns = @JoinColumn(name = "user_id"))
   @Column(name = "message")
   public List<String> messages;
}

地图集

最后,你不仅要存储一个集合,还要存储一个 HashMap,你需要在一个辅助表中为它存储两列:

CREATE TABLE user_message {
    user_id INT,
    key VARCHAR(255),
    message VARCHAR(255)
};

为了指定地图的键,您需要@MapKeyColumn注释。

例子:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message", joinColumns = @JoinColumn(name = "user_id"))
   @MapKeyColumn(name = "key")
   @Column(name = "message")
   public Map<String, String> messages;
}

您可以在官方文档中找到更多信息。