При разговоре об отображении объектов в реляционной базе данных, обеспечении постоянства объектов или выполнении запросов к ним вместо слова «объект» следует использовать термин «сущность». Объекты — это экземпляры, которые располагаются в памяти. Сущности представляют собой объекты, которые недолго располагаются в памяти, но постоянно — в базе данных. Все они могут быть отображены в базе данных. Они также могут быть конкретными или абстрактными; кроме того, они поддерживают наследование, связи и т. д. Произведя отображение этих сущностей, ими можно управлять посредством JPA. Вы можете обеспечить постоянство сущности в базе данных, удалить ее, а также выполнять запросы к этой сущности с использованием языка запросов Java Persistence Query Language, или JPQL. Объектно-реляционное отображение позволяет вам манипулировать сущностями при доступе к базе данных «за кадром». И, как вы увидите, у сущности имеется определенный жизненный цикл. JPA позволяет вам привязывать бизнес-код к событиям жизненного цикла с применением методов обратного вызова и слушателей.
В качестве первого примера начнем с простой сущности, которая только может быть у нас. В модели постоянства JPA сущность — это простой Java-объект в старом стиле (Plain Old Java Object — POJO). Это означает, что объявление сущности, создание ее экземпляра и использование осуществляются точно так же, как и в случае с любым другим Java-классом. У сущности имеются атрибуты (ее состояние), которыми можно манипулировать с помощью геттеров и сеттеров. Пример простой сущности приведен в листинге 4.1.
@Entity
public class Book {
··@Id @GeneratedValue
··private Long id;
··private String title;
··private Float price;
··private String description;
··private String isbn;
··private Integer nbOfPage;
··private Boolean illustrations;
··public Book() {
}
// Геттеры, сеттеры
}
В примере в листинге 4.1 представлена сущность Book, из которой я для ясности убрал геттеры и сеттеры. Как вы можете видеть, за исключением некоторых аннотаций, эта сущность выглядит точно так же, как любой другой Java-класс: у нее есть атрибуты (id, title, price и т. д.) разных типов (Long, String, Float, Integer и Boolean), конструктор по умолчанию, при этом имеются геттеры и сеттеры для каждого атрибута. Как все это отображается в таблицу? Ответ можно получить благодаря аннотациям.
Анатомия сущности
Чтобы класс был сущностью, его нужно снабдить аннотацией @javax.persistence.Entity, которая позволит поставщику постоянства признать его постоянным классом, а не простым POJO. Кроме того, аннотация @javax.persistence.Id будет определять уникальный идентификатор этого объекта. Поскольку JPA используется для отображения объектов в реляционные таблицы, объектам необходим идентификатор, который будет отображен в первичный ключ. Остальные атрибуты в листинге 4.1 (title, price, description и т. д.) не снабжены аннотациями, поэтому они будут сделаны постоянными путем применения отображения по умолчанию.
Этот пример кода включает атрибуты, однако, как вы увидите позднее, сущность также может располагать бизнес-методами. Обратите внимание, что эта сущность Book является Java-классом, который не реализует никакого интерфейса и не расширяет какого-либо класса. Фактически, чтобы быть сущностью, класс должен придерживаться таких правил.
• Класс-сущность должен быть снабжен аннотацией @javax.persistence.Entity (или обозначен в XML-дескрипторе как сущность).
• Для обозначения простого первичного ключа должна быть использована аннотация @javax.persistence.Id.
• Класс-сущность должен располагать конструктором без аргументов, который должен быть public или protected. У класса-сущности также могут иметься другие конструкторы.
• Класс-сущность должен быть классом верхнего уровня. Перечисление или интерфейс не могут быть обозначены как сущность.
• Класс-сущность не должен быть final. Ни один из методов или постоянные переменные экземпляра класса-сущности тоже не могут быть final.
• Если экземпляр сущности надлежит передать с использованием значения как обособленный объект (например, с помощью удаленного интерфейса), то класс-сущность должен реализовывать интерфейс Serializable.