Например, приложению CD-BookStore необходимо часто выкладывать информацию на главной странице, где вы сможете читать ежедневные новости о книгах, музыке или артистах. У новостей будет иметься содержимое, название и, поскольку они могут быть написаны на нескольких языках, код языка (EN для английского, PT — для португальского и т. д.). Первичным ключом для новостей тогда сможет быть название и код языка, поскольку статья может быть переведена на разные языки, но с сохранением ее оригинального названия. Таким образом, класс первичного ключа NewsId будет включать два атрибута, имеющие тип String: title и language. Классы первичных ключей должны включать определения методов для equals() и hashCode() для управления запросами и внутренними коллекциями (равенство в случае с этими методами должно быть таким же, как и равенство, которое имеет место в случае с базой данных), а их атрибуты должны быть допустимых типов, входящих в приведенный ранее набор. Они также должны быть открытыми, реализовывать интерфейс Serializable, если им потребуется пересекать архитектурные уровни (например, управление ими будет осуществляться на постоянном уровне, а использование — на уровне представления), и располагать конструктором без аргументов.

@EmbeddedId. Как вы еще увидите позднее в этой главе, JPA использует встроенные объекты разных типов. Резюмируя, отмечу, что у встроенного объекта нет какого-либо идентификатора (собственного первичного ключа), а его атрибуты в итоге окажутся столбцами таблицы содержащей их сущности.

В листинге 5.5 класс NewsId показан как встраиваемый. Он представляет собой всего лишь встроенный объект (аннотированный с использованием @Embeddable), который в данном случае включает два атрибута (title и language). У этого класса должен быть конструктор без аргументов, геттер, сеттер, а также реализации equals() и hashCode(). Это означает, что он должен придерживаться соглашений JavaBeans. У этого класса как такового нет собственного идентификатора (отсутствует аннотация @Id). Это характерно для встраиваемых классов.

Листинг 5.5. Класс первичного ключа снабжается аннотацией @Embeddable

@Embeddable

public class NewsId {

··private String title;

··private String language;

··// Конструкторы, геттеры, сеттеры

}

В случае с сущностью News, показанной в листинге 5.6, затем придется встроить класс первичного ключа NewsId с применением аннотации @EmbeddedId. Благодаря такому подходу не потребуется использовать @Id. Каждая аннотация @EmbeddedId должна ссылаться на встраиваемый класс, помеченный @Embeddable.

Листинг 5.6. Вложение класса первичного ключа с применением аннотации @EmbeddedId для сущности

@Entity

public class News {

··@EmbeddedId

··private NewsId id;

··private String content;

··// Конструкторы, геттеры, сеттеры

}

В следующей главе я опишу, как находить сущности с использованием их первичного ключа. Вот первый, но мимолетный взгляд на то, как это происходит: первичный ключ — это класс с конструктором. Вам придется создать экземпляр этого класса со значениями, формирующими ваш уникальный ключ, и передать соответствующий объект менеджера сущностей (атрибут em), как показано в этом коде:

NewsId pk = new NewsId("Richard Wright has died on September 2008", "EN")

News news = em.find(News.class, pk);

@IdClass. Другой метод объявления составного ключа — использование аннотации @IdClass. Это иной подход, в соответствии с которым каждый атрибут класса первичного ключа также должен быть объявлен в классе-сущности и аннотирован с помощью @Id.

Составной первичный ключ в примере NewsId, приведенном в листинге 5.7, является всего лишь POJO, которому не требуется какая-либо аннотация (в предыдущем примере в листинге 5.6 класс первичного ключа приходилось аннотировать с помощью @EmbeddedId).

Листинг 5.7. У класса первичного ключа аннотация отсутствует

public class NewsId {

private String title;

··private String language;

··// Конструкторы, геттеры, сеттеры

}

Затем для сущности News, показанной в листинге 5.8, придется определить первичный ключ с использованием аннотации @IdClass, и аннотировать каждый ключ посредством @Id. Для обеспечения постоянства сущности News вам потребуется задать значения для атрибутов title и language.

Листинг 5.8. Определение первичного класса с использованием аннотации @IdClass для сущности

@Entity

@IdClass(NewsId.class)

public class News {

Перейти на страницу:

Похожие книги