1. Introduction
1.介绍
Inheritance is one of the key concepts in Java. So, it’s no surprise that most domain models use it. But unfortunately, this concept doesn’t exist in relational databases, and you need to find a way to map the inheritance hierarchy to a relational table model.
继承是Java中的关键概念之一。所以,大多数领域模型使用它并不奇怪。但不幸的是,这个概念在关系数据库中并不存在,你需要找到一种方法来将继承层次映射到关系表模型中。
JPA and Hibernate support different strategies, that map the inheritance hierarchy to various table models. Let’s take a look at a chapter of my new book Hibernate Tips – More than 70 solutions to common Hibernate problems in which I explain the SingleTable strategy. It maps all classes of the inheritance hierarchy to the same database table.
JPA和Hibernate支持不同的策略,这些策略将继承层次映射到各种表模型上。让我们看看我的新书《Hibernate技巧–70多个Hibernate常见问题的解决方案》中的一章,其中我解释了SingleTable策略。它将继承层次的所有类映射到同一个数据库表中。
I explain Hibernate’s other inheritance mapping strategies in my Hibernate Tips book. It’s a cookbook with more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.
我在我的Hibernate Tips书中解释了Hibernate的其他继承映射策略。这是一本烹饪书,其中有70多个现成的食谱,主题包括基本和高级映射、日志、Java 8支持、缓存以及静态和动态定义查询。
2. Hibernate Tips – How to Map an Inheritance Hierarchy to One Table
2.Hibernate技巧–如何将继承层次结构映射到一个表中
2.1. Problem
2.1 问题
My database contains one table, which I want to map to an inheritance hierarchy of entities. How do I define such a mapping?
我的数据库包含一个表,我想把它映射到一个实体的继承层次。我如何定义这样一个映射?
2.2. Solution
2.2.解决方案
JPA and Hibernate support different inheritance strategies which allow you to map the entities to different table structures. The SingleTable strategy is one of them and maps an inheritance hierarchy of entities to a single database table.
JPA和Hibernate支持不同的继承策略,允许你将实体映射到不同的表结构。SingleTable策略是其中之一,它将实体的继承层次映射到一个单一的数据库表。
Let’s have a look at the entity model before I explain the details of the SingleTable strategy. Authors can write different kinds of Publications, like Books and BlogPosts. The Publication class is the super class of the Book and BlogPost classes.
在我解释SingleTable策略的细节之前,让我们看一下实体模型。作者可以写不同种类的出版物,如书籍和博客帖子。Publication类是Book和BlogPost类的超类。
The SingleTable strategy maps the three entities of the inheritance hierarchy to the publication table.
SingleTable策略将继承层次结构的三个实体映射到publication表中。
If you want to use this inheritance strategy, you need to annotate the superclass with an @Inheritance annotation and provide the InheritanceType.SINGLE_TABLE as the value of the strategy attribute.
如果你想使用这种继承策略,你需要用@Inheritance注解来注释超类,并提供InheritanceType.SINGLE_TABLE作为strategy属性的值。
You can also annotate the superclass with a @DiscriminatorColumn annotation to define the name of the discriminator value. Hibernate uses this value to determine the entity to which it has to map a database record. If you don’t define a discriminator column, as I do in the following code snippet, Hibernate, and all other JPA implementations use the column DTYPE.
你也可以用@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>();
...
}
The subclasses need to extend the superclass, and you need to annotate them with a @Entity annotation.
子类需要扩展超类,并且你需要用@Entity注解来注解它们。
The JPA specification also recommends to annotate it with a @DiscriminatorValue annotation to define the discriminator value for this entity class. If you don’t provide this annotation, your JPA implementation generates a discriminator value.
JPA规范还建议用@DiscriminatorValue注解来定义这个实体类的鉴别器值。如果你不提供这个注解,你的JPA实现会生成一个判别值。
But the JPA specification doesn’t define how to generate the discriminator value, and your application might not be portable to other JPA implementations. Hibernate uses the simple entity name as the discriminator.
但是JPA规范并没有定义如何生成判别器的值,而你的应用程序可能无法移植到其他JPA实现中。Hibernate使用简单的实体名称作为鉴别器。
@Entity
@DiscriminatorValue("Book")
public class Book extends Publication {
private int numPages;
...
}
The SingleTable strategy doesn’t require Hibernate to generate any complex queries if you want to select a specific entity, perform a polymorphic query or traverse a polymorphic association.
如果你想选择一个特定的实体,执行一个多态查询或遍历一个多态关联,SingleTable策略不需要Hibernate生成任何复杂的查询。
Author a = em.find(Author.class, 1L);
List<Publication> publications = a.getPublications();
All entities are stored in the same table, and Hibernate can select them from there without an additional JOIN clause.
所有实体都存储在同一个表中,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. Source Code
2.3.源代码
You can find a download link for a project with executable test cases for this Hibernate tip in the book.
你可以在书中找到一个项目的下载链接,该项目包含这个Hibernate提示的可执行测试案例。
2.4. Learn More
2.4.了解更多
You can also map the entities of the inheritance hierarchy to multiple database tables.
I show you how to do that in the chapter How to map an inheritance hierarchy to multiple tables.
你也可以将继承层次结构的实体映射到多个数据库表中。
我在如何将继承层次结构映射到多个表一章中告诉你如何做到这一点。
3. Summary
3.总结
As you have seen in this Hibernate Tip, JPA and Hibernate provide an easy option to map an inheritance hierarchy to a single database table. You just have to annotate the superclass with @Inheritance(strategy = InheritanceType.SINGLE_TABLE) and you should also annotate the subclasses with @DiscriminatorValue(“Book”).
正如你在这个Hibernate技巧中所看到的,JPA和Hibernate提供了一个简单的选项来将继承层次映射到一个单一的数据库表。你只需要用@Inheritance(strategy = InheritanceType.SINGLE_TABLE)来注释超类,你也应该用@DiscriminatorValue(“Book”)来注释子类。
You can get more recipes like this in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems. It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.
你可以在我的新书Hibernate技巧中得到更多这样的食谱。超过70种常见Hibernate问题的解决方案。它为你提供了70多个现成的配方,涉及基本和高级映射、日志、Java 8支持、缓存以及静态和动态定义查询等主题。