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

Что ж, ты познакомился с тем, как мапить простые типы. Теперь пора перейти к вопросам поинтереснее – как мапить коллекции объектов.

А объекты у нас могут быть в 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;
}

Более подробную информацию ты сможешь найти в официальной документации.

undefined
1
Задача
Модуль 4. Работа с БД, 13 уровень, 0 лекция
Недоступна
Расстановка аннотаций
Есть класс-энтити Author, у автора могут быть статьи articles. Добавь аннотации перед полем articles в классе Author, чтобы программа корректно обрабатывала данные из таблиц:
undefined
1
Задача
Модуль 4. Работа с БД, 13 уровень, 0 лекция
Недоступна
Расстановка аннотаций 2
Есть класс-энтити Author, у автора могут быть достижения achievements. Не все достижения одинаково ценные, поэтому они упорядочены с помощью achievement_index и хранятся в списке List.