Список колекцій

Що ж, ти познайомився з тим, як мапит прості типи. Тепер настав час перейти до питань цікавіше – як мапити колекції об'єктів.

А об'єкти у нас можуть бути у 5 групах:

  • Array – масив об'єктів
  • List – список об'єктів
  • Set - безліч об'єктів
  • Map – словник об'єктів
  • Collection – колекція об'єктів

І приклад класу із полем-колекцією:

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

   @Чарівна-анотація
   public List messages;
}

То що ж це за чарівна інструкція така, яка дозволить нам зберігати не одне поле, а багато значень?

Ця інструкція називається @ElementCollection . Приклад:

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

   @ElementCollection
   public List<String> messages;
}

Пишеться вона дуже просто, а от працює нетривіально.

Допоміжна таблиця

Усі поля Entity-класу, які містять багато елементів і позначаються за допомогою анотації @ElementCollection, містяться в базі даних у спеціальній допоміжній таблиці. Що, власне, логічно.

Ця таблиця може містити дані у двох видах:

  • Упорядковані (List, Map) містять три колонки:
    • Key Column (Foreign Key) – посилання на ID об'єкта-батька.
    • Index Column – позиція/індекс у колекції.
    • Element Column – значення.
  • Неупорядковані (Set) містять дві колонки:
    • Key Column (Foreign Key) – посилання на ID об'єкта-батька.
    • Element Column – значення.

Також ти можеш задати ім'я цієї таблиці за допомогою анотації:

@CollectionTable(name="ім'я_таблиці")

Приклад:

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

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

Важливо! Якщо анотація @CollectionTable не вказана, Hibernate сам побудує ім'я таблиці на основі імені класу та імені поля: клас User і полеmessagesдадуть ім'я таблиці "User_messages".

Колекція Set

Але давай не віддаватимемо на відкуп Hibernate створення допоміжної таблиці і створимо її самі. Спочатку нам потрібно створити таблицю із двома колонками:

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

Зверніть увагу, що ця таблиця не має своєї id-колонки. Це і є основною ознакою допоміжних таблиць. З іншими видами допоміжних таблиць ти познайомишся трохи згодом.

Тепер потрібно замапити цю таблицю на наше полеmessagesу класі User . Виглядатиме ця справа так:

@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;
}

Тут варто звернути увагу на дві речі.

По-перше, колонка message, вказана за допомогою анотації @Column(name = "message") , знаходиться у допоміжній таблиці user_message, а не в таблиці user.

По-друге, в інструкції @JoinColumn(name = "user_id") ми вказали ім'я колонки user_id, яка посилається на id таблиці user. Це щоб Hibernate знав, як їх правильно поєднувати.

Колекція List

Якщо ти хочеш зберігати в допоміжній таблиці впорядковані елементи списку або масиву, то знадобиться таблиця з трьома колонками:

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;
}

Колекція Map

І нарешті, ти хочеш зберігати не просто колекцію, а HashMap, і тобі для нього потрібні дві колонки у допоміжній таблиці:

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

Для того, щоб вказати ключ для Map, тобі знадобиться анотація @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;
}

Більш детальну інформацію ти зможеш знайти в офіційній документації .