Перейти к основному содержимому

Отрывок из книги Hibernate Tips: как сопоставить иерархию наследования с одной таблицей

· 4 мин. чтения

1. Введение

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

JPA и Hibernate поддерживают разные стратегии, которые сопоставляют иерархию наследования с различными моделями таблиц. Давайте взглянем на главу моей новой книги «Советы по Hibernate — более 70 решений распространенных проблем Hibernate», в которой я объясняю стратегию SingleTable . Он сопоставляет все классы иерархии наследования с одной и той же таблицей базы данных.

Я объясняю другие стратегии сопоставления наследования в Hibernate в моей книге Hibernate Tips . Это кулинарная книга с более чем 70 готовыми к использованию рецептами по таким темам, как базовые и расширенные сопоставления, ведение журналов, поддержка Java 8, кэширование, а также статически и динамически определяемые запросы. Вы можете приобрести его на этой неделе на Amazon по специальной стартовой цене всего в 2,99 доллара.


2. Советы по Hibernate — как сопоставить иерархию наследования с одной таблицей

2.1. Проблема

Моя база данных содержит одну таблицу, которую я хочу сопоставить с иерархией наследования сущностей. Как определить такое отображение?

2.2. Решение

JPA и Hibernate поддерживают разные стратегии наследования, которые позволяют отображать объекты в разные структуры таблиц. Стратегия SingleTable является одной из них и отображает иерархию наследования сущностей в одну таблицу базы данных.

Давайте взглянем на модель сущностей, прежде чем я объясню детали стратегии SingleTable . Авторы могут создавать различные виды публикаций , такие как книги и сообщения в блогах . Класс Publication является надклассом классов Book и BlogPost .

./a958e3b324c4dd4ea13fb229e4f87554.png

Стратегия SingleTable сопоставляет три объекта иерархии наследования с таблицей публикации .

./b348ec4c007f430ca9032e72c2a0ea0e.png

Если вы хотите использовать эту стратегию наследования, вам необходимо аннотировать суперкласс аннотацией @Inheritance и предоставить InheritanceType.SINGLE_TABLE в качестве значения атрибута стратегии .

Вы также можете аннотировать суперкласс аннотацией @DiscriminatorColumn , чтобы определить имя значения дискриминатора. Hibernate использует это значение для определения объекта, которому он должен сопоставить запись базы данных. Если вы не определяете столбец дискриминатора, как я делаю в следующем фрагменте кода, Hibernate и все другие реализации JPA используют столбец DTYPE .

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Publication {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

@Version
private int version;

private String title;

private LocalDate publishingDate;

@ManyToMany
@JoinTable(
name="PublicationAuthor",
joinColumns={@JoinColumn(name="publicationId", referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="authorId", referencedColumnName="id")})
private Set<Author> authors = new HashSet<Author>();

...
}

Подклассы должны расширять суперкласс, и вам нужно аннотировать их аннотацией @Entity .

Спецификация JPA также рекомендует аннотировать его аннотацией @DiscriminatorValue , чтобы определить значение дискриминатора для этого класса объектов. Если вы не предоставите эту аннотацию, ваша реализация JPA создаст значение дискриминатора.

Но спецификация JPA не определяет, как генерировать значение дискриминатора, и ваше приложение может быть несовместимо с другими реализациями JPA. Hibernate использует простое имя объекта в качестве дискриминатора.

@Entity
@DiscriminatorValue("Book")
public class Book extends Publication {

private int numPages;

...
}

Стратегия SingleTable не требует, чтобы Hibernate генерировал какие-либо сложные запросы, если вы хотите выбрать определенный объект, выполнить полиморфный запрос или пройти полиморфную ассоциацию.

Author a = em.find(Author.class, 1L);
List<Publication> publications = a.getPublications();

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

15:41:28,379 DEBUG [org.hibernate.SQL] - 
select
author0_.id as id1_0_0_,
author0_.firstName as firstNam2_0_0_,
author0_.lastName as lastName3_0_0_,
author0_.version as version4_0_0_
from
Author author0_
where
author0_.id=?
15:41:28,384 DEBUG [org.hibernate.SQL] -
select
publicatio0_.authorId as authorId2_2_0_,
publicatio0_.publicationId as publicat1_2_0_,
publicatio1_.id as id2_1_1_,
publicatio1_.publishingDate as publishi3_1_1_,
publicatio1_.title as title4_1_1_,
publicatio1_.version as version5_1_1_,
publicatio1_.numPages as numPages6_1_1_,
publicatio1_.url as url7_1_1_,
publicatio1_.DTYPE as DTYPE1_1_1_
from
PublicationAuthor publicatio0_
inner join
Publication publicatio1_
on publicatio0_.publicationId=publicatio1_.id
where
publicatio0_.authorId=?

2.3. Исходный код

Ссылку на скачивание проекта с исполняемыми тест-кейсами для этого совета по Hibernate вы можете найти в книге .

2.4. Учить больше

Вы также можете сопоставить сущности иерархии наследования с несколькими таблицами базы данных.

Я покажу вам, как это сделать, в главе Как отобразить иерархию наследования на несколько таблиц .

3. Резюме

Как вы видели в этом совете по Hibernate, JPA и Hibernate предоставляют простой способ сопоставления иерархии наследования с одной таблицей базы данных. Вам просто нужно аннотировать суперкласс с помощью @Inheritance(strategy = InheritanceType.SINGLE_TABLE) , а также вы должны аннотировать подклассы с помощью @DiscriminatorValue("Book") .

Больше подобных рецептов вы можете найти в моей новой книге « Советы по Hibernate: более 70 решений распространенных проблем с Hibernate » . Он дает вам более 70 готовых к использованию рецептов по таким темам, как базовые и расширенные сопоставления, ведение журналов, поддержка Java 8, кэширование, а также статически и динамически определенные запросы. Всего за несколько дней вы можете получить электронную книгу за 2,99 доллара и книгу в мягкой обложке за 12,99 доллара на Amazon .