«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.