Сущности поддерживают наследование классов, полиморфные ассоциации и полиморфные запросы. Классы сущностей могут расширять классы не-сущностей, а классы не-сущностей могут расширять классы сущностей. Классы сущностей могут быть как абстрактными, так и конкретными.
Здесь рассматриваются следующие темы:
Абстрактные сущности
Абстрактный класс может быть объявлен как сущность путём указания аннотации @Entity
для класса. Абстрактные сущности подобны конкретным сущностям, но не могут быть инстанцированы.
Выборка абстрактных сущностей происходит так же, как и конкретных сущностей. Если абстрактная сущность является целью запроса, запрос работает со всеми конкретными дочерними классами абстрактной сущности:
@Entity
public abstract class Employee {
@Id
protected Integer employeeId;
...
}
@Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
...
}
@Entity
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
}
Сопоставленные родительские классы
Сущности могут наследовать от родительских классов, которые содержат информацию о персистентном состоянии и отображении, но не являются сущностями. То есть родительский класс не аннотирован @Entity
и не будет распознан как сущность в Persistence provider. Эти родительские классы чаще всего используются, когда имеется информация о состоянии и отображении, общая для нескольких классов сущностей.
Сопоставленные родительские классы определяются путём указания аннотации javax.persistence.MappedSuperclass
для класса:
@MappedSuperclass
public class Employee {
@Id
protected Integer employeeId;
...
}
@Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
...
}
@Entity
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
...
}
Для сопоставленных родительских классов нельзя сделать выборку и нельзя использовать в операциях EntityManager
или Query
. Вы должны использовать дочерние классы сущности сопоставленного родительского класса в операциях EntityManager
или Query
. Сопоставленные родительские классы не могут быть объектами отношений сущностей. Сопоставленные родительские классы могут быть абстрактными или конкретными.
Сопоставленные родительские классы не имеют соответствующих таблиц в хранилище данных. Объекты, которые наследуются от сопоставленного родительского класса, определяют mapping на таблицы. Например, в предыдущем примере кода были бы таблицы FULLTIMEEMPLOYEE
и PARTTIMEEMPLOYEE
, но таблицы EMPLOYEE
нет.
Родительские классы, не являющиеся сущностями
Родительские классы сущностей могут не являться сущностями, и эти родительские классы могут быть абстрактными или конкретными. Родительские классы, не являющиеся сущностями, не имеют персистентного состояния, и любое состояние, унаследованное от такого родительского класса классом сущностей, не является персистентным. Не-сущностные родительские классы нельзя использовать в операциях EntityManager
или Query
. Любые аннотации отображения или отношений в родительских классах — не-сущностях игнорируются.
Стратегии отображения при наследовании сущностей
Вы можете настроить, как persistence provider отображает унаследованные сущности в хранилище данных, декорируя корневой класс иерархии аннотацией javax.persistence.Inheritance
. Следующие стратегии используются для отображения данных сущности на базу данных:
-
Единая таблица на иерархию классов
-
По таблице на конкретный класс сущностей
-
Стратегия «объединения», при которой поля и свойства, специфичные для дочерних классов, отображаются на таблицу, отличную от таблицы для полей и свойств родительского класса.
Стратегия настраивается путём установки элемента strategy
аннотации @Inheritance
в один из параметров, определённых в перечислимом типе javax.persistence.InheritanceType
:
public enum InheritanceType {
SINGLE_TABLE,
JOINED,
TABLE_PER_CLASS
};
Стратегия по умолчанию, InheritanceType.SINGLE_TABLE
, используется, если аннотация @Inheritance
не указана в корневом классе иерархии сущностей.
Стратегия "Единая таблица на иерархию классов"
С помощью этой стратегии, которая соответствует InheritanceType.SINGLE_TABLE
по умолчанию, все классы в иерархии отображаются в одну таблицу в базе данных. Эта таблица имеет столбец дискриминатора, содержащий значение, идентифицирующее дочерний класс, которому принадлежит объект, представленный строкой.
Столбец дискриминатора, элементы которого показаны в таблице 40-2, можно указать аннотацией javax.persistence.DiscriminatorColumn
в корне иерархии классов сущностей.
Таблица 40-2 @DiscriminatorColumn Elements
Тип |
Название |
Описание |
String
|
name
|
Имя столбца, который будет использоваться в качестве столбца дискриминатора. По умолчанию используется значение DTYPE . Этот элемент не является обязательным. |
DiscriminatorType
|
discriminatorType
|
Тип столбца, который будет использоваться в качестве столбца дискриминатора. По умолчанию используется значение DiscriminatorType.STRING . Этот элемент не является обязательным. |
String
|
columnDefinition
|
Фрагмент SQL для использования при создании столбца дискриминатора. Значение по умолчанию создаётся Persistence provider-ом и зависит от реализации. Этот элемент не является обязательным. |
String
|
length
|
Длина столбца для типов дискриминаторов на основе String . Этот элемент игнорируется, если тип дискриминатора не-String . По умолчанию установлено значение 31. Этот элемент не является обязательным. |
Перечислимый тип javax.persistence.DiscriminatorType
используется для установки типа столбца дискриминатора в базе данных путём установки элемента discriminatorType
аннотации @DiscriminatorColumn
к одному из определённых типов. DiscriminatorType
определяется следующим образом:
public enum DiscriminatorType {
STRING,
CHAR,
INTEGER
};
Если @DiscriminatorColumn
не указан в корне иерархии сущностей и требуется столбец дискриминатора, Persistence provider принимает имя столбца по умолчанию DTYPE
и тип столбца DiscriminatorType.STRING
.
Аннотацию javax.persistence.DiscriminatorValue
можно использовать для установки значения, введённого в столбец дискриминатора для каждого объекта в иерархии классов. Аннотация @DiscriminatorValue
может быть установлена только конкретным классам сущностей.
Если @DiscriminatorValue
не указан для объекта в иерархии классов, в котором используется столбец дискриминатора, Persistence provider предоставит значение по умолчанию, зависящее от реализации. Если элемент discriminatorType
в @DiscriminatorColumn
равен DiscriminatorType.STRING
, значением по умолчанию является имя объекта.
Эта стратегия обеспечивает хорошую поддержку полиморфных отношений между сущностями и запросами, которые охватывают всю иерархию классов сущностей. Однако эта стратегия требует, чтобы столбцы, которые содержат состояние дочерних классов, могли принимать значение null.
Стратегия "По таблице на конкретный класс сущностей"
В этой стратегии, которая соответствует InheritanceType.TABLE_PER_CLASS
, каждый конкретный класс сопоставляется с отдельной таблицей в базе данных. Все поля или свойства в классе, включая унаследованные поля или свойства, сопоставляются со столбцами в таблице класса в базе данных.
Эта стратегия плохо поддерживает полиморфные отношения и обычно требует либо запросов SQL UNION
, либо отдельных запросов SQL для каждого дочернего класса для запросов, которые охватывают всю иерархию классов сущностей.
Поддержка этой стратегии является необязательной и может поддерживаться не всеми Persistence provider-ами. Persistence provider по умолчанию на сервере GlassFish не поддерживает эту стратегию.
Стратегия объединения дочерних классов
В этой стратегии, которая соответствует InheritanceType.JOINED
, корень иерархии классов представлен одной таблицей, и каждый дочерний класс имеет отдельную таблицу, которая содержит только те поля, которые относятся к этому дочернему классу. То есть таблица дочернего класса не содержит столбцы для унаследованных полей или свойств. Таблица дочернего класса также имеет столбец или столбцы, которые представляют её первичный ключ, который является внешним ключом первичного ключа таблицы родительского класса.
Эта стратегия обеспечивает хорошую поддержку полиморфных отношений, но требует выполнения одной или нескольких операций соединения при создании объектов дочерних классов сущностей. Это может привести к низкой производительности для обширных иерархий классов. Точно так же запросы, которые покрывают всю иерархию классов, требуют операций соединения между таблицами дочерних классов, что приводит к снижению производительности.
Некоторым Persistence provider-ам, включая Persistence provider по умолчанию в GlassFish Server, требуется столбец дискриминатора, который соответствует корневому объекту при использовании стратегии объединённого дочернего класса. Если вы не используете автоматическое создание таблиц в своём приложении, убедитесь, что таблица базы данных настроена правильно для значений по умолчанию для столбца дискриминатора, или используйте аннотацию @DiscriminatorColumn
для соответствия схеме вашей базы данных. Для получения информации о столбцах дискриминатора см. Единая таблица на иерархию классов.