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

1. Вступление

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

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

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


2. Hibernate Советы - Как отобразить иерархию наследования в одну таблицу

2.1. Проблема

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

2.2. Решение

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

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

ссылка:/uploads/InheritanceEntityModel-300x253.png%20300w[]

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

ссылка:/uploads/New-InheritanceSingleTable-768x350.png%20768w[]

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

Вы также можете аннотировать суперкласс с помощью аннотации @ 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 в book .

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

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

3. Резюме

Как вы видели в этом совете по Hibernate, JPA и Hibernate предоставляют простой способ сопоставить иерархию наследования с одной таблицей базы данных.

Вы просто должны аннотировать суперкласс с помощью @ Inheritance (стратегии = InheritanceType.SINGLE TABLE) , а также вы должны аннотировать подклассы с помощью @ DiscriminatorValue («Book») __.