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») __.