Сущности

В Jmix существуют следующие типы сущностей:

  • Сущности JPA – это объекты Java, хранящиеся в базе данных с использованием Java Persistence API.

  • Сущности DTO – это простые объекты Java, которые не привязаны к какой-либо конкретной технологии персистентности.

  • Сущность Key-Value (ключ-значение) – это динамическая сущность с произвольным количеством атрибутов.

Сущности характеризуются своими атрибутами.

Сущности JPA и DTO сущности определяются классами Java и имеют некоторые специфичные для Jmix аннотации.

Для создания сущностей JPA и DTO используйте дизайнер сущностей Studio.

Сущности JPA

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

Аннотации JPA определяют отображение между полями таблицы базы данных и атрибутами сущности. Jmix налагает следующие ограничения на аннотации JPA:

  • Аннотации атрибутов должны размещаться только в полях (AccessType.FIELD).

  • Не поддерживаются: @IdClass, @ElementCollection.

Ниже приведен пример типичного класса сущности JPA:

Customer.java
@JmixEntity (1)
@Table(name = "SAMPLE_CUSTOMER") (2)
@Entity(name = "sample_Customer") (3)
public class Customer {

    @JmixGeneratedValue (4)
    @Id (5)
    @Column(name = "ID", nullable = false) (6)
    private UUID id;

    @Version (7)
    @Column(name = "VERSION")
    private Integer version;

    @InstanceName (8)
    @NotNull (9)
    @Column(name = "NAME", nullable = false)
    private String name;

    @Email (9)
    @Column(name = "EMAIL", unique = true) (10)
    private String email;

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    // other getters and setters
1 Обязательная аннотация @JmixEntity.
2 Аннотация @javax.persistence.Table указывает имя таблицы базы данных.
3 Аннотация @javax.persistence.Entity указывает, что класс – сущность JPA, и его имя.
4 Аннотация @JmixGeneratedValue указывает, что Jmix должен сгенерировать и назначить первичный ключ при создании экземпляра сущности в памяти.
5 Аннотация @javax.persistence.Id указывает первичный ключ.
6 Аннотация @javax.persistence.Column определяет сопоставление со столбцом таблицы. Параметр nullable = false указывает, что механизм миграции базы данных должен создать столбец с ограничением NOT NULL.
7 @javax.persistence.Version указывает, что сущность должна быть оптимистически заблокирована, используя значение этого атрибута. Атрибут должен иметь тип Integer. Studio создает такой атрибут автоматически, если вы выберите для сущности черту Versioned.
8 Аннотация @InstanceName указывает здесь на один атрибут, выбранный в качестве имени экземпляра.
9 Аннотации @NotNull и @Email из пакета javax.validation.constraints являются примерами использования в сущностях аннотаций Bean Validation.
10 Параметр unique = true в аннотации @Column указывает, что механизм миграции базы данных должен добавить в столбец ограничение уникальности.

Как имя таблицы, так и имя сущности могут иметь префикс для устранения конфликтов с именами сущностей из других модулей. Studio ставит этот префикс, если проект имеет свойство jmix.projectId в build.gradle.

Черты

Черта (Trait) – это набор атрибутов, который придает сущности определенное поведение на системном уровне. Эти атрибуты обрабатываются фреймворком и не предназначены для редактирования пользователями или кодом вашего приложения.

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

Черта Has UUID

Черта Has UUID предоставляет глобально уникальный идентификатор, автоматически назначаемый при создании экземпляра в памяти. Эта черта реализуется атрибутом с типом UUID и аннотацией @JmixGeneratedValue.

При создании сущности в Studio черта Has UUID применяется автоматически, если вы выбрали UUID в Id type. Добавьте черту Has UUID, если вы выбрали другой тип и Id value, отличное от значения Generated by Jmix.

Эта черта не требует дополнительного атрибута, если вы выбираете тип UUID для идентификатора сущности.

Добавление черты Has UUID настоятельно рекомендуется, если вы используете атрибут идентификатора, значение которого не назначено непосредственно при создании экземпляра сущности в памяти. Это относится к идентификаторам Long и Integer, отображенным на столбец идентификаторов, а также к идентификаторам любого типа, назначенным пользователями. Если у такой сущности нет атрибута с @JmixGeneratedValue, ее метод hashCode() всегда возвращает постоянное значение, что влияет на производительность коллекций на основе хэш-таблиц.

Черта Versioned

Черта Versioned обеспечивает оптимистическую блокировку на уровне JPA. Она реализуется целочисленным атрибутом с аннотацией @Version.

Никогда не изменяйте значение атрибута @Version в коде приложения. Это приведет к невозможности обновления экземпляра в базе данных.

Черты Audit

Черты Audit of creation и Audit of modification обеспечивают отслеживание того, кто и когда создал и изменил экземпляр сущности. Они реализуются атрибутами соответствующих типов с аннотациями @CreatedBy, @CreatedDate, @LastModifiedBy и @LastModifiedDate из проекта Spring Data.

Например:

@CreatedBy
@Column(name = "CREATED_BY")
private String createdBy;

@CreatedDate
@Temporal(TemporalType.DATE)
@Column(name = "CREATED_DATE")
private Date createdDate;

@LastModifiedBy
@Column(name = "LAST_MODIFIED_BY")
private String lastModifiedBy;

@LastModifiedDate
@Temporal(TemporalType.DATE)
@Column(name = "LAST_MODIFIED_DATE")
private Date lastModifiedDate;

Атрибуты Audit назначаются автоматически, когда фреймворк сохраняет экземпляры сущностей.

Черта Soft Delete

Черта Soft Delete обеспечивает мягкое удаление экземпляров сущностей. Она реализуется с помощью пары атрибутов с аннотациями @DeletedDate и @DeletedBy, например:

@DeletedBy
@Column(name = "DELETED_BY")
private String deletedBy;

@DeletedDate
@Temporal(TemporalType.DATE)
@Column(name = "DELETED_DATE")
private Date deletedDate;

Для более подробной информации перейдите к разделу Мягкое удаление.

Сущности DTO

Модель данных вашего приложения может содержать сущности, которые существуют только в памяти или отражают некоторые внешние данные, используя механизмы, отличные от JPA. Мы называем их сущностями DTO, потому что они часто используются в качестве Объектов передачи данных (Data Transfer Objects) в параметрах и возвращаемых значениях в Generic REST и при взаимодействии с внешними API.

Сущность DTO может быть такой простой, как:

OperationResult.java
@JmixEntity (1)
public class OperationResult {

    private String result; (2)

    private Integer errorCode; (2)

    private String errorMessage; (2)

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    // other getters and setters
1 Обязательная аннотация @JmixEntity.
2 Все свойства объекта (поля с методами доступа) становятся атрибутами сущности.

Атрибуты сущностей могут иметь аннотации для указания каких-либо подробностей о них:

ProductPart.java
@JmixEntity(name = "sample_ProductPart") (1)
public class ProductPart {

    @JmixProperty(mandatory = true) (2)
    @InstanceName (3)
    private String name;

    private Integer quantity; (4)

    // getters and setters
1 Аннотация @JmixEntity прямо определяет имя сущности.
2 Аннотация @JmixProperty с параметром mandatory = true указывает, что атрибут является обязательным, т.е. должен содержать значение.
3 Аннотация @InstanceName указывает здесь на один атрибут, выбранный в качестве имени экземпляра.
4 Атрибут без аннотации.

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

В приведенном ниже примере вы также увидите, как исключить некоторые свойства объекта из атрибутов сущности (подробнее об этом в разделе Атрибуты сущности).

Metric.java
@Store(name = "inmem") (1)
@JmixEntity(name = "sample_Metric", annotatedPropertiesOnly = true) (2)
public class Metric {

    @JmixProperty(mandatory = true) (3)
    @JmixId (4)
    @JmixGeneratedValue (5)
    private UUID id;

    @JmixProperty (6)
    private String name;

    @JmixProperty (6)
    private Double value;

    private Object ephemeral; (7)

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }

    // other getters and setters
1 Аннотация @Store указывает пользовательское хранилище данных.
2 Параметр annotatedPropertiesOnly = true аннотации @JmixEntity указывает, что свойства объекта, не помеченные с помощью @JmixProperty, не будут атрибутами сущности.
3 Аннотация @JmixProperty с параметром mandatory = true указывает, что атрибут является обязательным, т.е. должен содержать значение.
4 Аннотация @JmixId указывает, что атрибут является идентификатором сущности.
5 Аннотация @JmixGeneratedValue указывает, что Jmix должен сгенерировать и назначить идентификатор при создании экземпляра сущности в памяти.
6 Аннотация @JmixProperty здесь просто указывает, что свойство является атрибутом сущности.
7 Не аннотированное свойство не является атрибутом сущности из-за параметра annotatedPropertiesOnly = true аннотации @JmixEntity.

Сущность Key-Value

KeyValueEntity позволяет представлять произвольные наборы именованных значений в виде сущностей и, следовательно, работать с данными, которые не представлены непосредственно классами Java (сущностями JPA или DTO).

Рассмотрим пример: в вашей модели данных есть сущность Order, и вам нужно рассчитать сумму заказов, агрегированных клиентами, и отобразить эти данные в UI. Вы можете выполнить запрос JPQL и загрузить результат в виде списка экземпляров сущности KeyValueEntity используя DataManager:

List<KeyValueEntity> entities = dataManager.loadValues(
            "select e.customer, sum(e.amount) from sample_Order e group by e.customer")
        .properties("customer", "total")
        .list();

Возвращаемые экземпляры KeyValueEntity будут иметь два атрибута, которые вы указали в методе properties(): customer со значением первого поля в списке результатов запроса и total со значением второго поля. Вы можете получить их следующим образом:

for (KeyValueEntity entity : entities) {
    Customer customer = entity.getValue("customer");
    BigDecimal totalAmount = entity.getValue("total");
    // ...
}

Backoffice UI содержит специальные key-value контейнеры данных для привязки компонентов пользовательского интерфейса к экземплярам сущности KeyValueEntity.

Атрибуты сущности

Существует еще один термин для атрибутов сущности: свойства (properties) сущности. Он часто используется в кодовой базе Jmix, например, в аннотациях: @JmixProperty, @DependsOnProperties и т.д.

Каждый атрибут сущности должен иметь соответствующий тип. Jmix поддерживает следующие типы "из коробки":

  • java.lang.String

  • java.lang.Character

  • java.lang.Boolean

  • java.lang.Integer

  • java.lang.Long

  • java.lang.Double

  • java.math.BigDecimal

  • java.util.Date

  • java.time.LocalDate

  • java.time.LocalTime

  • java.time.LocalDateTime

  • java.time.OffsetTime

  • java.time.OffsetDateTime

  • java.sql.Date

  • java.sql.Time

  • java.util.UUID

  • java.net.URI

  • byte[] (массив байтов)

  • Перечисление

  • Сущность или набор сущностей (ссылочный атрибут)

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

Обратите внимание, что примитивные типы Java (int, boolean, и т.д.) не могут использоваться для атрибутов сущностей.

Для сущностей JPA и DTO существует два типа атрибутов:

  • Атрибут на основе поля соответствует полю и паре методов доступа accessor (геттер / сеттер) поля. Имя поля становится именем атрибута.

    Сеттер может быть опущен, тогда атрибут будет доступен только для чтения.

    Пример атрибута на основе поля:

    User.java
    @Column(name = "FIRST_NAME")
    protected String firstName;
    
    public String getFirstName() {
        return firstName;
    }
    
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
  • Атрибут на основе метода соответствует методу без параметров, возвращающему поддерживаемый тип и с именем, начинающимся с get, например getCustomer(). Имя метода без get с первой буквой в нижнем регистре становится именем атрибута: getFullName()fullName.

    Пример атрибута на основе метода:

    User.java
    @JmixProperty
    @DependsOnProperties({"firstName", "lastName"})
    public String getFullName() {
        return this.firstName + " " + this.lastName;
    }

Класс сущностей может иметь свойства (поле + геттер/сеттер) и методы, которые не являются атрибутами сущности, то есть не включены в метаданные. Таким образом, вы можете использовать такие свойства и методы в коде вашего приложения, но фреймворк не распознает их и не будет отображать в UI или передавать через REST API.

Становится ли свойство или квалифицирующий метод атрибутом сущности, зависит от следующих правил:

  • Если параметр annotatedPropertiesOnly аннотации @JmixEntity имеет значение false (по умолчанию), следующие свойства объекта становятся атрибутами сущности:

    • Для сущностей JPA: все свойства, кроме аннотированных @javax.persistence.Transient.

    • Для сущностей DTO: все свойства.

    • В обоих случаях: все свойства и методы с аннотацией @JmixProperty.

  • Если параметр annotatedPropertiesOnly имеет значение true, только свойства и методы с аннотацией @JmixProperty становятся атрибутами сущности.

Ссылки

Ссылочные атрибуты определяют отношения между сущностями. Ссылки могут быть одиночными значениями (отношения "много-к-одному") или коллекциями (отношения "много-ко-многим").

По умолчанию связь является ассоциацией, что означает, что обе сущности могут существовать независимо друг от друга, без владения. Например, в связи Customer - Order у Order (заказа) есть атрибут, который является ссылкой на Customer (клиента). Пользователи самостоятельно создают клиентов и заказы, выбирают клиента для заказа и при необходимости меняют ссылку на другого клиента.

Jmix также поддерживает более сильную связь между сущностями – композицию. Композиция подразумевает владение, т.е. экземпляр сущности может существовать только как часть сущности-владельца. Например, в связи Order - OrderLine (строка заказа) у Order есть атрибут, который представляет собой коллекцию экземпляров OrderLine. Каждый экземпляр OrderLine создается для определенного Order, становится его частью и не может принадлежать другому Order.

Объекты, принадлежащие композиции, редактируются в UI вместе. Например, пользователь открывает экран редактирования Order и может создавать и редактировать OrderLines в их отдельных экранах редактирования, но все изменения как для Order, так и для всех его OrderLines сохраняются в базе данных вместе в одной транзакции и только после того, как пользователь подтвердит сохранение объекта-владельца – Order.

Отношение-композиция определяется аннотацией @Composition к ссылочному атрибуту.

Дизайнер сущностей Studio позволяет выбрать тип отношения в поле Attribute type.

Ссылки между сущностями из разных хранилищ

DataManager автоматически поддерживает TO-ONE ссылки между сущностями из разных хранилищ, если они объявлены нужным образом.

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

Рассмотрим пример: у вас есть сущность Customer в основном хранилище данных и сущность Address в дополнительном хранилище данных, и вы хотите получить ссылку от Customer на Address. Тогда сущность Customer должна содержать следующие два атрибута:

@SystemLevel
@Column(name = "ADDRESS_ID")
private UUID addressId; (1)

@Transient
@JmixProperty
@DependsOnProperties("addressId")
private Address address; (2)

public UUID getAddressId() {
    return addressId;
}

public void setAddressId(UUID addressId) {
    this.addressId = addressId;
}

public Address getAddress() {
    return address;
}

public void setAddress(Address address) {
    this.address = address;
}
1 Атрибут addressId хранит идентификатор сущности Address. Этот атрибут аннотирован как @SystemLevel, чтобы указать фреймворку, что атрибут не должен отображаться пользователям.
2 Атрибут address содержит ссылку на сущность Address. Этот атрибут является неперсистентным (т.е. не хранится в базе данных) и аннотирован как @DependsOnProperties, чтобы указать фреймворку, что значение этого атрибута зависит от другого атрибута.

После этого, когда вы загружаете Customer с фетч планом, включающим атрибут address, DataManager автоматически загружает связанный Address из дополнительного хранилища данных. Фреймворк оптимизирует загрузку коллекций для повышения производительности: после загрузки списка клиентов он загружает ссылки из дополнительного хранилища данных частями. Размер частей определяется свойством приложения jmix.core.crossDataStoreReferenceLoadingBatchSize (по умолчанию 50).

Когда вы сохраняете граф сущностей, который включает Customer с Address, DataManager сохраняет экземпляры с помощью соответствующих реализаций DataStore, а затем сохраняет идентификатор адреса в атрибуте addressId клиента.

Создание экземпляров сущностей

При создании экземпляров сущностей JPA и DTO используйте соответствующий интерфейс фреймворка вместо вызова конструктора класса с оператором new. Только в этом случае фреймворк сможет инициализировать поля с аннотациями @JmixGeneratedValue и вызывать методы @PostConstruct.

Наиболее общим методом создания экземпляров сущностей является Metadata.create():

@Autowired
private Metadata metadata;

Order createOrder() {
    return metadata.create(Order.class);
}

Если вы пишете бизнес-логику и в вашем коде уже есть DataManager, используйте его метод create(), что просто избавит вас от необходимости инжектировать бин Metadata. Например:

@Autowired
private DataManager dataManager;

Order createAndSaveOrder(String number) {
    Order order = dataManager.create(Order.class);
    order.setNum(number);
    dataManager.save(order);
    return order;
}

На экране Backoffice UI вы можете использовать один из двух методов, описанных выше. Чтобы созданный экземпляр автоматически сохранялся при коммите DataContext экрана, используйте метод DataContext.create(). Он создает экземпляр и сразу же помещает его в контекст, чтобы начать отслеживать изменения экземпляра. В приведенном ниже примере мы создаем экземпляр сущности ProductPart, помещаем его в DataContext и добавляем в контейнер данных для отображения в UI таблице:

@Autowired
private DataContext dataContext;

@Autowired
private CollectionPropertyContainer<ProductPart> partsDc;

@Subscribe("partsTable.create")
public void onPartsTableCreate(Action.ActionPerformedEvent event) {
    ProductPart part = dataContext.create(ProductPart.class);
    partsDc.getMutableItems().add(part);
}

Uniqueness

Jmix relies on database unique constraints for maintaining uniqueness of entity instances. So if you want to make an entity attribute or a set of attributes unique, you should create an appropriate index for the database table.

Studio Дизайнер сущностей contains the Indexes tab where you can define unique indexes. The index definitions are stored in the @Table annotation of the entity and later used by Liquibase changelog generator for creating indexes in the database schema.

The unique = true attribute of the @Column annotation is not interpreted by Jmix in any way.

See Handling Unique Constraint Violation Exceptions section for how to customize messages displayed by the framework for unique constraint violation errors.

If you want to define a unique attribute for an entity with the Soft Delete trait, refer to the Soft Deletion section.

Аннотации сущностей Jmix

Аннотации сущностей Jmix описаны ниже в алфавитном порядке.

Сущности в Jmix также могут иметь аннотации для сопоставлений JPA, черт audit и мягкого удаления.

@Composition

Аннотация @Composition на ссылочном атрибуте указывает, что связь является композицией. Например:

@Composition
@OneToMany(mappedBy = "order")
private List<OrderLine> lines;

@DbView

@DbView annotation indicates whether a JPA entity is mapped to a database view. Database migration scripts are not generated for such entities.

@DdlGeneration

@DdlGeneration annotation defines whether development tools should generate DDL scripts for this entity.

The scripts generation mode is set with the DbScriptGenerationMode enumeration:

  • CREATE_AND_DROP - full generation of initialization and update scripts;

  • CREATE_ONLY - full generation of initialization scripts. Update scripts are generated without statements to drop columns;

  • DISABLED - initialization and update scripts are not generated.

Default value: CREATE_AND_DROP.

In addition, you can fine-tune the scripts generation using the following attributes:

  • unmappedColumns - the list of columns that exist in the database but should not be mapped to the entity. Drop scripts for these columns will not be generated;

  • unmappedConstraints - the list of constraints and indexes that exist in the database but should not be mapped to the entity. Drop scripts for these columns will not be generated.

@DependsOnProperties

Аннотация @DependsOnProperties определяет свойства сущности, от которых зависит аннотированный атрибут. Эти свойства учитываются при построении фетч планов и при загрузке/сохранении ссылок на сущности из разных хранилищ данных. Кроме того, если аннотированное свойство доступно только для чтения (без сеттера), для этого свойства отправляется EntityPropertyChangeEvent при изменении указанных атрибутов.

Вы можете указать только непосредственные локальные и ссылочные свойства. Такие пути к свойствам, как customer.name не поддерживаются.

@InstanceName

Instance name – это понятный пользователю текст, представляющий экземпляр сущности. Думайте об этом как о методе toString() на уровне приложения. Он часто используется в UI при отображении экземпляра сущности в одном поле или ячейке таблицы. Вы также можете получить имя экземпляра программно, используя метод MetadataTools.getInstanceName().

Аннотация @InstanceName может присутствовать в одном поле или методе объекта.

В первом случае в качестве имени экземпляра используется аннотированное значение атрибута. Например:

@InstanceName
@Column(name = "NAME")
private String name;

Если вы хотите сгенерировать что-то более сложное, чем одно значение атрибута, создайте метод, возвращающий String в классе сущности. Например:

@JmixEntity(name = "sample_GeoPoint")
@Embeddable
public class GeoPointEntity {

    @Column(name = "LAT")
    protected Double latitude;

    @Column(name = "LON")
    protected Double longitude;

    @InstanceName
    @DependsOnProperties({"latitude", "longitude"})
    public String getDisplayName(Messages messages) {
        return messages.formatMessage(
                getClass(), "GeoPointEntity.instanceName", this.latitude, this.longitude);
    }

Метод принимает любые Spring бины в качестве параметров. В приведенном выше примере бин Messages используется для форматирования имени экземпляра в соответствии с текущей локалью пользователя.

Аннотация @DependsOnProperties к методу имени экземпляра необходима, поскольку она определяет атрибуты встроенного фетч-плана _instance_name.

@JmixEntity

@JmixEntity – это обязательная аннотация, указывающая, что класс является сущностью Jmix.

Если класс аннотирован @javax.persistence.Entity, фреймворк получает от него имя сущности для метаданных, и @JmixEntity не должен указывать параметр name. В противном случае укажите имя сущности в параметре name. Если ни у @JmixEntity, ни у @javax.persistence.Entity нет параметра name, имя сущности равно простому имени класса Java.

Параметр annotatedPropertiesOnly указывает, какие свойства объекта становятся атрибутами сущности. См. Атрибуты сущности для получения более подробной информации.

@JmixGeneratedValue

Аннотация @JmixGeneratedValue указывает, что фреймворк должен сгенерировать и назначить значение атрибута сущности при создании экземпляра сущности в памяти.

Аннотированный атрибут должен быть типа Long, Integer или UUID, и сущность не должна иметь более одного UUID атрибута, отмеченного этой аннотацией.

Обратите внимание, что аннотация @JmixGeneratedValue не вступает в силу, если вы создаете экземпляр сущности с помощью оператора new. См. надлежащие методы создания новых экземпляров в разделе Создание экземпляров сущностей.

@JmixId

Аннотация @JmixId указывает идентификатор сущности для сущностей DTO. Вы должны явно выбрать идентификатор, если ваша сущность DTO сопоставлена с некоторыми внешними данными и вам нужно многократно загружать/сохранять ее экземпляры, потому что в этом случае вам необходимо поддерживать идентификацию объекта на протяжении всего жизненного цикла сущности.

Вы можете использовать существующий атрибут как идентификатор, если атрибут содержит уникальные значения, например:

@JmixId
private String code;

Если такого естественно уникального атрибута нет, определите его и также аннотируйте @JmixGeneratedValue, чтобы присвоить уникальное значение при создании экземпляра:

@JmixId
@JmixGeneratedValue
private UUID id;

@JmixProperty

Аннотация @JmixProperty указывает, что поле или метод объекта является атрибутом сущности. Дополнительные сведения см. в разделе Атрибуты сущности.

Используйте параметр mandatory, если хотите указать, что для атрибута требуется значение, а поле объекта не содержит JPA аннотацию @Column, в которой вы могли бы задать nullable = false.

@PostConstruct

Используйте аннотацию javax.annotation.PostConstruct на методе, который выполняет инициализацию нового экземпляра сущности. Например:

@PostConstruct
void init() {
    setGrade(CustomerGrade.BRONZE);
}

Аннотированный метод принимает любые Spring бины. В приведенном ниже примере мы используем бин TimeSource для инициализации атрибута date:

@PostConstruct
void init(TimeSource timeSource) {
    setDate(timeSource.now().toLocalDate());
}
Обратите внимание, что аннотированный метод @PostConstruct не вызывается, если вы создаете экземпляр сущности с помощью оператора new. См. надлежащие методы создания новых экземпляров в разделе Создание экземпляров сущностей.

@PropertyDatatype

Если у вас есть несколько типов данных для Java-типа атрибута сущности, аннотация @PropertyDatatype позволяет прямо указать реализацию Datatype по ее идентификатору.

@PropertyDatatype("year")
@Column(name = "YEAR_")
private Integer productionYear;

@Store

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

@SystemLevel

Аннотация @SystemLevel указывает, что аннотированная сущность или ее атрибут являются низкоуровневыми и не должны отображаться в пользовательском интерфейсе.