Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Наследование сущностей

Сущности поддерживают наследование классов, полиморфные ассоциации и полиморфные запросы. Классы сущностей могут расширять классы не-сущностей, а классы не-сущностей могут расширять классы сущностей. Классы сущностей могут быть как абстрактными, так и конкретными.

Приложение roster демонстрирует наследование объектов, как описано в Наследование сущностей в приложении roster.

Здесь рассматриваются следующие темы:

Абстрактные сущности

Абстрактный класс может быть объявлен как сущность путём указания аннотации @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 для соответствия схеме вашей базы данных. Для получения информации о столбцах дискриминатора см. Единая таблица на иерархию классов.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)