Entities
There are the following types of entities in Jmix:
-
JPA entities are Java objects stored in a database using Java Persistence API.
-
DTO entities are simple Java objects that are not tied to any specific persistence technology.
-
Key-Value Entity is a dynamic entity with an arbitrary number of attributes.
Entities are characterized by their attributes.
JPA and DTO entities are defined by Java classes and have some annotations specific to Jmix.
Use Studio entity designer to create JPA and DTO entities. |
Do not implement equals() and hashCode() methods in your entity classes explicitly or with Lombok annotations. These methods are generated automatically by Jmix at build time and use entity identifiers for comparison.
|
JPA Entities
JPA entity is a Java class annotated according to JPA rules. JPA entities are stored in a relational database connected as a main or additional data store.
JPA annotations define mapping between database table fields and entity attributes. Jmix imposes the following restrictions on mapping annotations:
-
Attribute annotations must be placed only on fields (
AccessType.FIELD
). -
Not supported:
@IdClass
,@ElementCollection
.
Below is an example of a typical JPA entity class:
@JmixEntity (1)
@Table(name = "CUSTOMER") (2)
@Entity (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 | Mandatory @JmixEntity annotation. |
2 | @jakarta.persistence.Table annotation specifies the database table name. |
3 | @jakarta.persistence.Entity annotation indicates that the class is a JPA entity. |
4 | The @JmixGeneratedValue annotation indicates that the primary key must be generated and assigned by Jmix when creating entity instance in memory. |
5 | @jakarta.persistence.Id annotation indicates the primary key. |
6 | @jakarta.persistence.Column annotation specifies a mapping to a table column. The nullable = false parameter indicates that the database migration mechanism should create the column with the NOT NULL constraint. |
7 | @jakarta.persistence.Version indicates that the entity must be optimistically locked using the value of this attribute. The attribute should be of Integer type. Studio creates such an attribute automatically if you select the Versioned trait for the entity. |
8 | The @InstanceName annotation here indicates a single attribute chosen as the instance name. |
9 | @NotNull and @Email annotations from the javax.validation.constraints package are the examples of using Bean Validation annotations in entities. |
10 | The unique = true parameter of the @Column annotation indicates that the database migration mechanism should add the unique constraint to the column. |
Both table and entity name can have a prefix to eliminate name conflicts with entities of other modules. Studio inserts this prefix if the project has the jmix.projectId
property in build.gradle
.
Traits
A trait is a set of attributes that gives the entity some specific system-level behavior. These attributes are handled by the framework and are not intended to be edited by users or your application code.
Studio entity designer helps you assign available traits to an entity. You can also do it manually by creating corresponding attributes and annotating them as described below.
Has UUID Trait
The Has UUID trait provides a globally unique identifier, assigned automatically when an instance is created in memory. The trait is implemented by an attribute of the UUID
type annotated with @JmixGeneratedValue.
When creating an entity in Studio, the Has UUID trait is selected automatically if you choose UUID in Id type. Add the Has UUID trait if you choose a different type and Id value different from Generated by Jmix. |
This trait does not require an additional attribute if you choose UUID
type for the entity identifier.
Adding the Has UUID trait is highly recommended if you use an identifier attribute whose value is not assigned right at the creation of entity instance in memory. This is the case for Long
or Integer
identifiers mapped to an identity column, and for identifiers of any type assigned by users. If such an entity has no @JmixGeneratedValue
attribute, its hashCode()
method always returns a constant value, which affects the performance of collections based on hash tables.
Versioned Trait
The Versioned trait provides optimistic locking on the JPA level. It is implemented by an integer attribute annotated with @Version
.
Never change the value of the @Version attribute in the application code. It will lead to the inability to update the instance in the database.
|
Audit Traits
The Audit of creation and Audit of modification traits provide tracking of who and when created and modified an entity instance. They are implemented by attributes of appropriate types annotated with @CreatedBy
, @CreatedDate
, @LastModifiedBy
, @LastModifiedDate
annotations from the Spring Data project.
For example:
@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 attributes are assigned automatically when the framework saves entity instances.
Soft Delete Trait
The Soft Delete trait provides soft deletion of entity instances. It is implemented by a pair of attributes annotated with @DeletedDate
and @DeletedBy
, for example:
@DeletedBy
@Column(name = "DELETED_BY")
private String deletedBy;
@DeletedDate
@Temporal(TemporalType.DATE)
@Column(name = "DELETED_DATE")
private Date deletedDate;
See more information in the Soft Deletion section.
Entity Inheritance
Jmix framework uses principles of JPA inheritance. Studio entity designer automatically generates the necessary annotations in accordance with the chosen inheritance strategy. The main annotations are listed below.
@DiscriminatorColumn
Is used for defining a database column responsible for the distinction of entity types in the cases of SINGLE_TABLE
and JOINED
inheritance strategies.
Parameters:
-
name
- the discriminator column name. -
discriminatorType
- the discriminator column type. -
length
- the column length for String-based discriminator types.
Example:
@DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue
Defines the discriminator column value for this entity.
Example:
@DiscriminatorValue("0")
@Inheritance
Defines the inheritance strategy to be used for an entity class hierarchy. It is specified on the entity class that is the root of the entity class hierarchy.
Parameters:
-
strategy
- the inheritance strategy,SINGLE_TABLE
by default.
@MappedSuperclass
Defines that the class is an ancestor for some entities, and its attributes must be used as part of descendant entities. Such a class is not associated with any particular database table.
@PrimaryKeyJoinColumn
Is used in the case of JOINED
inheritance strategy to specify a foreign key column for the entity, which refers to the primary key of the ancestor entity.
Parameters:
-
name
- the name of the foreign key column of the entity. -
referencedColumnName
- the name of a primary key column of the ancestor entity
Example:
@PrimaryKeyJoinColumn(name = "CARD_ID", referencedColumnName = "ID")
DTO Entities
The data model of your application can contain entities that exist only in memory or are mapped to some external data using mechanisms different from JPA. We call such entities DTO because they are often used as Data Transfer Objects in parameters and return values in REST API and when communicating with external APIs.
A DTO entity can be as simple as that:
@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 | Mandatory @JmixEntity annotation. |
2 | All object properties (fields with accessor methods) become entity attributes. |
Entity attributes can have annotations to specify some details about them:
@JmixEntity (1)
public class ProductPart {
@JmixProperty(mandatory = true) (2)
@InstanceName (3)
private String name;
private Integer quantity; (4)
// getters and setters
1 | The @JmixEntity annotation defines the entity name explicitly. |
2 | The @JmixProperty annotation with mandatory = true parameter indicates that the attribute is required, i.e. it must contain a value. |
3 | The @InstanceName annotation here indicates a single attribute chosen as the instance name. |
4 | An attribute without annotations. |
DTO entities can be associated with a custom data store for generic CRUD operations via DataManager
and automatic resolving of references to the DTO entity from JPA entities.
In the example below, you can also see how to exclude some object properties from being entity attributes (more on this in the Entity Attributes section):
@Store(name = "inmem") (1)
@JmixEntity(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 | The @Store annotation specifies a custom data store. |
2 | The annotatedPropertiesOnly = true parameter of @JmixEntity annotation indicates that object properties not annotated with @JmixProperty will not be entity attributes. |
3 | The @JmixProperty annotation with mandatory = true parameter indicates that the attribute is required, i.e. it must contain a value. |
4 | The @JmixId annotation indicates that the attribute is the entity identifier. |
5 | The @JmixGeneratedValue annotation indicates that the identifier must be generated and assigned by Jmix when creating the entity instance in memory. |
6 | The @JmixProperty annotation here just indicates that the property is an entity attribute. |
7 | Not annotated property is not an entity attribute because of annotatedPropertiesOnly = true parameter of @JmixEntity annotation. |
Key-Value Entity
KeyValueEntity
lets you represent arbitrary sets of named values as entities and hence work with data that is not directly represented by Java classes (JPA or DTO entities).
Consider an example: you have Order
entity in your data model, and you need to calculate sum of order amounts aggregated by customers and show this data in UI. Then you can execute a JPQL query and load the result list as a list of KeyValueEntity
instances using DataManager
:
List<KeyValueEntity> entities = dataManager.loadValues(
"select e.customer, sum(e.amount) from Order_ e group by e.customer")
.properties("customer", "total")
.list();
The returned KeyValueEntity
instances will have two attributes which you specified in the properties()
method: customer
with the value of the first field in the query result set, and total
with the value of the second field. You can get them as follows:
for (KeyValueEntity entity : entities) {
Customer customer = entity.getValue("customer");
BigDecimal totalAmount = entity.getValue("total");
// ...
}
Jmix UI has special key-value data containers for binding UI components to KeyValueEntity
instances.
Entity Attributes
There is another term for entity attributes: entity properties. It’s often used in the Jmix codebase, for example in annotations: @JmixProperty , @DependsOnProperties , etc.
|
Each entity attribute should have an appropriate type. Jmix supports the following types out-of-the-box:
-
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[]
(byte array) -
Entity or a collection of entities (a reference attribute)
You can use a type not from the list above if you create an appropriate Datatype implementation and make sure your type is supported by the underlying data store.
Note that Java primitive types (int , boolean , etc.) cannot be used for entity attributes.
|
In JPA and DTO entities, there are two types of attributes:
-
Field-based attribute corresponds to a field and a pair of accessor methods (getter / setter) of the field. The field name becomes the attribute name.
The setter can be omitted, then the attribute is read-only.
Example of a field-based attribute:
User.java@Column(name = "FIRST_NAME") protected String firstName; public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; }
-
Method-based attribute corresponds to a method without parameters, returning a supported type, and with a name starting from
get
, for examplegetCustomer()
. The method name withoutget
with the first letter in lower case becomes the attribute name:getFullName()
→fullName
.Example of a method-based attribute:
User.java@JmixProperty @DependsOnProperties({"firstName", "lastName"}) public String getFullName() { return this.firstName + " " + this.lastName; }
An entity class can have properties (field + getter/setter) and methods that are not entitiy attributes, that is not included in metadata. So you can use such properties and methods in your application code, but the framework will not recognize them and will not display them in UI or transfer through the REST API.
Whether a property or a qualifying method becomes an entity attribute is subject to the following rules:
-
If the
annotatedPropertiesOnly
parameter of @JmixEntity annotation isfalse
(which is the default), the following object properties become entity attributes:-
For JPA entities: all properties except annotated with
@jakarta.persistence.Transient
. -
For DTO entities: all properties.
-
For both: all properties and methods annotated with @JmixProperty.
-
-
If the
annotatedPropertiesOnly
parameter is set totrue
, only the properties and methods annotated with @JmixProperty become entity attributes.
References
Reference attributes define relationships between entities. References can be single-value (to-one relationships) or collections (to-many relationships).
By default, a relationship is an association, which means that both entities can exist independently of each other, without any ownership. For example, in a Customer - Order relationship, Order has an attribute which is a reference to Customer. Users create customers and orders independently, select a customer for an order, and change the reference to another customer if needed.
Jmix also supports a stronger connection between entities called composition. Composition implies ownership, when an entity instance can exist only as a part of its owning entity instance. For example, in a Order - OrderLine relationship, Order has an attribute which is a collection of OrderLine instances. Each OrderLine instance is created for a particular Order and becomes its part, it cannot belong to another Order.
Entities belonging to a composition are edited together in UI. For example, a user opens an Order edit screen and can create and edit OrderLines in their separate edit screens, but all changes both for the Order and all its OrderLines are saved to the database together in one transaction, and only after the user confirms saving of the owning entity - Order.
Composition relationship is specified by the @Composition annotation on the reference attribute.
Studio entity designer allows you to select a relationship type in the Attribute type field. |
Cross-Datastore References
DataManager
can automatically maintain To-One references between entities from different data stores, if they are properly defined.
Studio entity designer automatically defines the set of attributes for cross-datastore references when you select an entity from a different data store as an association. |
Let’s take an example: you have Customer
entity in the main data store and Address
entity in an additional data store, and you want to have a reference from Customer
to Address
. Then Customer
entity should contain the following two attributes:
@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 | The addressId attribute stores the identifier of Address . This attribute is annotated with @SystemLevel to indicate to the framework that the attribute should not be displayed to users. |
2 | The address attribute contains the reference to the Address entity. This attribute is transient (not stored in the database) and annotated with @DependsOnProperties to indicate to the framework that the attribute value depends on another attribute. |
After that, when you load Customer
with a fetch plan including address
attribute, DataManager
automatically loads related Address
from the additional data store. The framework optimizes loading of collections for performance: after loading a list of customers, it loads references from the additional data store in batches. The size of the batch is defined by the jmix.core.cross-data-store-reference-loading-batch-size application property.
When you save an entity graph which includes Customer
with Address
, DataManager
saves the instances via corresponding DataStore
implementations, and then saves the identifier of the address in the customer’s addressId
attribute.
Instantiating Entities
When creating instances of JPA and DTO entities, use the appropriate framework interface instead of invoking the class constructor with the new
operator. Only in this case the framework can initialize fields annotated with @JmixGeneratedValue and invoke @PostConstruct methods.
The most common core method for instantiating entities is Metadata.create()
:
@Autowired
private Metadata metadata;
Order createOrder() {
return metadata.create(Order.class);
}
If you write business logic and already have DataManager in your code, use its create()
method, which just saves you from additionally injecting the Metadata
bean. For example:
@Autowired
private DataManager dataManager;
Order createAndSaveOrder(String number) {
Order order = dataManager.create(Order.class);
order.setNum(number);
dataManager.save(order);
return order;
}
In a UI view, you can use either of two methods described above. But you may also want the created instance to be saved automatically by DataContext of the view. Then use the DataContext.create()
method which creates an instance and immediately merges it to start tracking its changes. In the example below, we create an instance of ProductPart
entity, merge it into DataContext
and add to a data container to display in a UI table:
@ViewComponent
private DataContext dataContext;
@ViewComponent
private CollectionPropertyContainer<ProductPart> partsDc;
@Subscribe("createProductPart")
public void onCreateProductPartClick(final ClickEvent<JmixButton> 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 Entity Designer 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.
|
If you want to define a unique attribute for an entity with the Soft Delete trait, refer to the Soft Deletion section.
Jmix Entity Annotations
Jmix entity annotations are described below in alphabetical order.
Jmix entities can also have annotations for JPA mappings, audit traits and soft deletion. |
@Comment
@Comment
annotation is used to provide a description for data model entities and their attributes, for example:
@Comment("""
Stores information about locations.
Has reference to address""")
@JmixEntity
@Table(name = "LOCATION")
@Entity
public class Location {
@Comment("Location zip code")
@InstanceName
@Column(name = "ZIP_CODE", nullable = false, length = 10)
@ValidZipCode
private String zipCode;
For all databases except HSQL, Studio generates setTableRemarks
and setColumnRemarks
Liquibase changelog operations to store the comments in the database schema. So the comments become available through any database inspection tool.
You can also extract comments from metadata (or directly from class annotations) to display in the application UI or generate a documentation. Use MetadataTools.getMetaAnnotationValue()
methods for convenience.
Studio supports creating comments in the Entity Designer. See the Comment edit links in the lists of entity and attribute parameters. When a comment is set, the link shows its first few words. |
@Composition
@Composition
annotation on a reference attribute indicates that the relationship is a composition.
For example:
@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
annotation specifies entity attributes that the annotated attribute depends on. These properties are taken into account when building fetch plans and when loading/saving references to entities from different data stores. Also, if the annotated property is read-only (without a setter), EntityPropertyChangeEvent
is sent for this attribute when the specified attributes are changed.
You can specify only immediate local and reference properties. Property paths like customer.name
are not supported.
@InstanceName
Instance name is a human-readable text that represents an entity instance. Think of it as of an application-level toString()
method. It is used extensively in UI when displaying an entity instance in a single field or table cell. You can also get the instance name programmatically using the MetadataTools.getInstanceName()
method.
The @InstanceName
annotation can be present on a single field or a method of the object.
In the former case, the annotated attribute value is used as the instance name. For example:
@InstanceName
@Column(name = "NAME")
private String name;
If you want to generate something more complex than a single attribute value, create a method returning String
in the entity class. For example:
@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);
}
The method can accept any Spring beans as parameters. In the example above, the Messages
bean is used to format the instance name according to the current user locale.
The @DependsOnProperties annotation on the instance name method is necessary, because it specifies attributes of the built-in _instance_name
fetch plan.
@JmixEntity
@JmixEntity
is a mandatory annotation indicating that the class is a Jmix entity.
If the class has @jakarta.persistence.Entity
annotation, the framework obtains entity name for the metadata from it, and @JmixEntity
should not specify the name
parameter. Otherwise, specify the entity name in the name
parameter. If neither @JmixEntity
nor @jakarta.persistence.Entity
have name
parameter, the entity name equals the Java class simple name.
The annotatedPropertiesOnly
parameter specifies what object properties become entity attributes, see Entity Attributes for more details.
@JmixGeneratedValue
@JmixGeneratedValue
annotation indicates that the entity attribute value must be generated and assigned by the framework when creating entity instance in memory.
The annotated attribute must be of Long
, Integer
or UUID
type, and the entity should not have more than one UUID
attribute marked with this annotation.
Note that the @JmixGeneratedValue annotation doesn’t take any effect if you create an entity instance using the new operator. See instantiating entities for proper methods of creating new instances.
|
@JmixId
@JmixId
annotation specifies an entity identifier for DTO entities. You should explicitly choose an identifier if your DTO entity is mapped to some external data and you need to load/save its instances repeatedly, because in this case you need to maintain the object identity through the entity lifecycle.
You can use an existing attribute for an identifier if the attribute contains unique values, for example:
@JmixId
private String code;
If there is no such naturally unique attribute, define one and annotate it also with @JmixGeneratedValue to assign a unique value on instance creation:
@JmixId
@JmixGeneratedValue
private UUID id;
@JmixProperty
@JmixProperty
annotation indicates that an object field or method is an entity attribute. See Entity Attributes for more details.
Use the mandatory
parameter if you want to specify that the attribute requires a value, and the object field has no JPA @Column
annotation where you could set nullable = false
.
@NumberFormat
Specifies a format for an attribute of the Number
type (it can be BigDecimal
, Integer
, Long
, or Double
). Values of such attribute will be formatted and parsed throughout the UI according to the provided annotation parameters:
-
pattern
- the format pattern as described for DecimalFormat. -
decimalSeparator
- the symbol to use for decimal separator (optional). -
groupingSeparator
- the symbol to use for grouping (thousands) separator (optional).
If decimalSeparator and/or groupingSeparator are not specified, their values are obtained from the current user’s locale for locale-dependent formatting, or from server default locale for locale-independent formatting.
|
Examples:
@Column(name = "PRECISE_NUMBER", precision = 19, scale = 4)
@NumberFormat(pattern = "0.0000")
protected BigDecimal preciseNumber;
@Column(name = "WEIRD_NUMBER", precision = 19, scale = 4)
@NumberFormat(pattern = "#,##0.0000", decimalSeparator = "_", groupingSeparator = "`")
protected BigDecimal weirdNumber;
@Column(name = "SIMPLE_NUMBER")
@NumberFormat(pattern = "#")
protected Integer simpleNumber;
@Column(name = "PERCENT_NUMBER", precision = 19, scale = 4)
@NumberFormat(pattern = "#%")
protected BigDecimal percentNumber;
@OnDelete
The @OnDelete
annotation can be used on reference attributes of soft-deleted entities. It specifies what should happen to the referenced entity when the entity instance containing the annotation (this entity) is deleted.
The annotation can have one of the following values:
-
DeletePolicy.DENY
– to throw an exception on attempt to delete the entity if the reference is not null. -
DeletePolicy.CASCADE
– to delete the referenced entities together with this entity. -
DeletePolicy.UNLINK
– to disconnect the referenced entity by setting the reference attribute to null. Use this value only on the owning side of the relationship (the one with the@JoinColumn
annotation).
@OnDeleteInverse
The @OnDelete
annotation can be used on reference attributes of soft-deleted and regular hard-deleted entities. It specifies what should happen to the entity instance containing the annotation (this entity) when the referenced entity is deleted.
The annotation can have one of the following values:
-
DeletePolicy.DENY
– to throw an exception on attempt to delete the referenced entity. -
DeletePolicy.CASCADE
– to delete this entity together with the referenced entity. -
DeletePolicy.UNLINK
– to set the reference attribute to null.
For soft-deleted entities, @OnDeleteInverse
is handled by the framework at runtime. The DENY
and CASCADE
values can be used on both owning (the one with the @JoinColumn
annotation) and non-owning (mappedBy
) sides of the relationship. The UNLINK
value should be used only on the owning side.
For regular hard-deleted entities, @OnDeleteInverse
with CASCADE
and UNLINK
values is handled by Studio when generating Liquibase changelogs. It must be used only on the owning (the one with the @JoinColumn
annotation) side of the relationship and leads to creating a foreign key constraint with the ON DELETE CASCADE
or ON DELETE SET NUll
parameters.
@PostConstruct
Use jakarta.annotation.PostConstruct
annotation on a method that performs initialization of a new entity instance. For example:
@PostConstruct
void init() {
setGrade(CustomerGrade.BRONZE);
}
The annotated method can accept any Spring beans. In the example below, we use TimeSource
bean to initialize a date
attribute:
@PostConstruct
void init(TimeSource timeSource) {
setDate(timeSource.now().toLocalDate());
}
Note that the @PostConstruct annotated method is not invoked if you create an entity instance using the new operator. See instantiating entities for proper methods of creating new instances.
|
@PropertyDatatype
If you have multiple datatypes for a Java type of an entity attribute, @PropertyDatatype
annotation lets you specify a Datatype
implementation explicitly by its id. For example:
@PropertyDatatype("year")
@Column(name = "YEAR_")
private Integer productionYear;
@Store
Use @Store
annotation on an entity class to associate the entity with an additional data store.