«1. Обзор

В этой статье мы поговорим о том, как сделать сущность, коллекцию или атрибут неизменяемыми в Hibernate.

По умолчанию поля изменяемы, что означает, что мы можем выполнять над ними операции, изменяющие их состояние.

2. Maven

Чтобы запустить наш проект, нам сначала нужно добавить необходимые зависимости в наш pom.xml. И поскольку мы работаем с Hibernate, мы собираемся добавить соответствующую зависимость:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.8.Final</version>
</dependency>

И, поскольку мы работаем с HSQLDB, нам также необходимо:

<dependency>
    <groupId>org.hsqldb</groupId>
    <artifactId>hsqldb</artifactId>
    <version>2.3.4</version>
</dependency>

3. Аннотации к сущностям ~~ ~ Во-первых, давайте определим простой класс сущности:

Как вы заметили, мы уже добавили аннотацию @Immutable к нашей сущности, поэтому, если мы попытаемся сохранить событие:

@Entity
@Immutable
@Table(name = "events_generated")
public class EventGeneratedId {

    @Id
    @Column(name = "event_generated_id")
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private Long id;

    @Column(name = "name")
    private String name;
    @Column(name = "description")
    private String description;

    // standard setters and getters
}

Тогда мы должны получить вывод:

@Test
public void addEvent() {
    Event event = new Event();
    event.setId(2L);
    event.setTitle("Public Event");
    session.save(event);
    session.getTransaction().commit();
    session.close();
}

Вывод должен быть таким же, даже если мы удалим аннотацию, что означает отсутствие эффекта при попытке добавить объект независимо от аннотации.

Hibernate: insert into events (title, event_id) values (?, ?)

Также важно отметить, что в нашу сущность EventGeneratedId мы добавили аннотацию GeneratedValue, но это будет иметь значение только при создании сущности. Это потому, что он определяет стратегию генерации для идентификатора — любые другие операции не повлияют на поле идентификатора из-за аннотации Immutable.

3.1. Обновление объекта

Теперь у нас не возникло проблем с сохранением объекта, давайте попробуем обновить его:

Hibernate просто проигнорирует операцию обновления, не вызывая исключения. Однако, если мы удалим аннотацию @Immutable, мы получим другой результат:

@Test
public void updateEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    event.setTitle("Public Event");
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

Это говорит нам о том, что наш объект теперь изменчив (изменяемый — это значение по умолчанию, если мы не включаем аннотацию) и позволит обновление, чтобы сделать свою работу.

Hibernate: select ... from events where title='My Event'
Hibernate: update events set title=? where event_id=?

3.2. Удаление объекта

Когда дело доходит до удаления объекта:

Мы сможем выполнить удаление независимо от того, является ли он изменяемым или нет:

@Test
public void deleteEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    session.delete(event);
    session.getTransaction().commit();
}

4. Аннотации к коллекциям ~~ ~ До сих пор мы видели, что аннотация делает с сущностями, но, как мы упоминали в начале, ее также можно применять к коллекциям.

Hibernate: select ... from events where title='My Event'
Hibernate: delete from events where event_id=?

Во-первых, давайте добавим коллекцию в наш класс Event:

Как и раньше, мы заранее добавили аннотацию, так что если мы продолжим и попытаемся добавить элемент в нашу коллекцию:

На этот раз мы получаем исключение, потому что с коллекциями нам не разрешено ни добавлять, ни удалять их.

@Immutable
public Set<String> getGuestList() {
    return guestList;
}

4.1. Удаление коллекций

org.hibernate.HibernateException: 
  changed an immutable collection instance: [com.baeldung.entities.Event.guestList#1]

Другой сценарий, когда коллекция, будучи неизменной, будет вызывать исключение всякий раз, когда мы пытаемся удалить, и мы установили аннотацию @Cascade.

Итак, всякий раз, когда @Immutable присутствует и мы пытаемся удалить:

Вывод:

5. Примечания XML

@Test
public void deleteCascade() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='Public Event'").list().get(0);
    String guest = event.getGuestList().iterator().next();
    event.getGuestList().remove(guest);
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

Наконец, конфигурация также может быть выполнена с использованием XML через изменяемый =false attribute:

org.hibernate.HibernateException: 
  changed an immutable collection instance:
  [com.baeldung.entities.Event.guestList#1]

Однако, поскольку мы в основном реализовывали примеры с помощью метода аннотации, мы не будем вдаваться в подробности, используя XML.

6. Заключение

<hibernate-mapping>
    <class name="com.baeldung.entities.Event" mutable="false">
        <id name="id" column="event_id">
            <generator class="increment"/>
        </id>
        <property name="title"/>
    </class>
</hibernate-mapping>

В этой быстрой статье мы рассмотрим полезную аннотацию @Immutable из Hibernate и то, как она может помочь нам определить лучшую семантику и ограничения для наших данных.

Как всегда, реализацию всех этих примеров и фрагментов можно найти в проекте GitHub. Это проект на основе Maven, поэтому его легко импортировать и запускать.

«

As always, the implementation of all of these examples and snippets can be found in the GitHub project. This is a Maven-based project so it should be easy to import and run.