Hibernate JPA Annotations

Hibernate JPA Annotations

Hibernate is a high-performance Object/Relational persistence and query service. Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types) but also provides data query and retrieval facilities. Hibernate, like all other object/relational mapping tools, requires metadata that governs the transformation of data from one representation to the other, whereas Hibernate Annotations provides annotation-based mapping metadata.

Annotations


@Entity - Defines that a class can be mapped to a database table
Hibernate JPA Annotations

@Table

The @Table annotation in JPA (Java Persistence API) is used to specify the details of the table that will be used to persist an entity in the database. It has several attributes (or annotations within) that you can use to customize the mapping. Here are the primary attributes you can use inside @Table:

  • name : Specifies the name of the table.

  • catalog : Specifies the catalog of the table. It’s mainly used when you want to define the catalog for DB schemas.

  • schema : Specifies the schema of the table. Useful in databases that support schemas.

  • unique Constraints : This allows you to specify that a particular combination of columns should have unique values. This is a way to define unique constraints on your table other than the primary key.

  • indexes : Used to specify indexes on the table for performance optimization.

  • foreign Keys : (Added in JPA 2.1) Allows defining foreign key constraints. Note that in many cases, the relationships like @ManyToOne or @OneToMany define the foreign keys, but this attribute gives you a way to provide further customizations.

  • inherits : A rare attribute, usually related to inheritance strategies in JPA. Not a standard JPA attribute but can be found in some specific JPA implementations or extensions.

  • applies To : Another non-standard attribute. It might be used in certain JPA extensions but not part of the core JPA spec.

Here’s a comprehensive example that integrates all of the attributes within the @Table annotation: Assuming we have a hypothetical Product entity, and we want to represent it in a table with all the possible attributes:

Hibernate JPA Annotations

Notes:

  • The Producttable is defined within the catalog "product_catalog" and the schema "product_schema".

  • Two unique constraints are defined: one for product_code and another for product_name.

  • Two indexes are defined: one for product_code and another compound index for product_name and product_description.

  • There’s a foreign key defined for the column category_id that references the id column of another table called category.

Please keep in mind that not all databases support catalogs and schemas in the same way, so the usage of catalog and schema might be specific to your DBMS. Also, while foreign Keys within the @Table provides some clarity in the definition, defining relationships using annotations like @ManyToOne and @OneToMany will implicitly create foreign keys for you. The foreign Keys attribute is more for overriding or providing custom definitions.

@Column

The @Column annotation is used in JPA (Java Persistence API) to specify the mapped column for a persistent property or field. It comes with various attributes to define and customize the column's details in the database. Here's a list of the attributes available within the @Column annotation:

  • name : Specifies the name of the column in the database.

  • unique : Indicates whether the column is a unique key.

  • nullable : Indicates whether the database column is nullable.

  • insertable : Whether the column is included in SQL INSERT statements generated by the persistence provider.

  • updatable : Whether the column is included in SQL UPDATE statements generated by the persistence provider.

  • column Definition : Used to define the SQL fragment for the column definition.

  • length : Specifies the column length. Particularly useful for string values.

  • precision : The precision for a decimal (exact numeric) column. This represents the number of digits in a number.

  • scale : The scale for a decimal (exact numeric) column. This represents the number of digits to the right of the decimal point.

  • table : Indicates the specific table in the database where the column resides. This attribute becomes essential when the entity’s properties or fields are spread across multiple tables, allowing you to pinpoint which secondary table the column belongs to.

Here’s a sample entity (User) demonstrating various @Column attributes:

Hibernate JPA Annotations

@Id-Specify the primary key of an entity

Hibernate JPA Annotations

@GeneratedValue- This allows you to generate the primary key values. Choose a generation strategy from Auto (default), Identity, Sequence and Table

Hibernate JPA Annotations

@Version- is used to implement Optimistic locking with Hibernate, which means that no two transactions override the data at the same time with a conflict.

Hibernate JPA Annotations

@OrderBy- Order the contents by a specific parameter

Hibernate JPA Annotations

@Transient-Transient annotation in JPA or Hibernate is used to indicate that a field is not to be persisted or ignore fields to save in the database.

Hibernate JPA Annotations

Hibernate Annotations for Mapping between tables In JPA, when dealing with relationships between entities, two key concepts that arise are “cascading” operations and “fetch types.” These concepts are used to define how related entities are fetched and how operations on one entity affect its related entities.

Cascade Types

Cascade types determine which operations carried out on the parent entity should be cascaded to the related entities. Here are the cascade types:

  • CascadeType.PERSIST : When persisting an entity, it also persists the entities held in this field. If the parent is persisted, the child will also be persisted.

  • CascadeType.MERGE : If the parent entity is merged (e.g., after being detached), the merge will also be cascaded to entities referenced by this field.

  • CascadeType.REMOVE : If the parent entity is removed, it also removes the entities held in this field.

  • CascadeType.REFRESH : If the parent entity is refreshed (its state is synced with the database), it also refreshes the entities held in this field.

  • CascadeType.DETACH : If you’re detaching an entity from the persistence context, the detachment is cascaded across the association.

  • CascadeType.ALL : All the above cascade operations are applied. Which is shorthand for applying all cascade options.

Fetch Types

Fetch types determine when the related entities should be fetched from the database:

  • FetchType.LAZY : The related entities will be loaded on-demand when accessed for the first time. This is typically implemented using proxies, and it’s the preferred way for associations with many entities to avoid loading too much data unnecessarily.

  • FetchType.EAGER : The related entities are fetched from the database as soon as the parent entity is fetched. This means that they’re always loaded, even if you don’t necessarily use them.

Combining Cascade and Fetch Types

You can combine cascade and fetch types to control both the life cycle and fetching behavior of related entities. Here’s an example :

Hibernate JPA Annotations

In the above case:

  • Operations on the parent entity will cascade to the related Order entities (because of CascadeType.ALL).

  • The related Order entities will be loaded lazily, i.e., only when accessed (due to FetchType.LAZY).

It’s important to choose the right cascade and fetch types depending on the use case, as they significantly influence both application performance and data integrity.

@OneToOne

The @OneToOne annotation in JPA is used to denote a one-to-one relationship between two entities. It comes with various attributes that help in defining and customizing this relationship. Here are the primary attributes of the @OneToOne annotation:

  • targetEntity : The entity class that is targeted by this association. It’s not often needed since the target type can usually be inferred from the generic type argument.

  • cascade: Defines the set of cascade operations that should be propagated to the target of the association.

  • fetch: Specifies whether the association should be lazily loaded (FetchType.LAZY) or eagerly loaded (FetchType.EAGER).

  • orphanRemoval : Indicates if a related entity should be removed when it’s no longer referenced from the source entity (usually used in parent-child relationships).

  • mappedBy : Specifies the field by which the relationship is mapped in the target entity. This attribute indicates that this side of the relationship is the “non-owning” side.

  • optional : Indicates whether the association is optional; “true” means it’s not mandatory for the relationship to have a value, “false” means the relationship must always exist.

Here’s an example to illustrate the usage of @OneToOne:

Suppose we have a User and Profile entity where one user has one profile and each profile is associated with only one user.
Hibernate JPA Annotations

In the example, a User entity has a one-to-one relationship with the Profile entity. The mappedBy attribute indicates that the Profile entity "owns" the relationship, so the foreign key will be on the Profile side in the database. Choosing appropriate cascading options, fetch type, and whether or not to use orphanRemoval depends on the specific needs and requirements of your application.

@manyToOne

The @ManyToOne annotation in JPA is used to define a many-to-one relationship between two entities. Here are the primary attributes you can use inside the @ManyToOne annotation:

  • targetEntity

  • cascade

  • fetch

  • optional

Here’s an illustrative example using the @ManyToOne annotation :

Let’s say we have Employee and Company entities, where many employees can belong to one company :
Hibernate JPA Annotations

In the example, an Employee entity has a many-to-one relationship with the Company entity. The relationship suggests that multiple Employee entities can be associated with a single Company entity. The mappedBy attribute in the Company entity's @OneToMany annotation points to the "owning" side of the relationship, which is the company field in the Employee entity.

@ManyToMany

The @ManyToMany annotation in JPA is used to define a many-to-many relationship between two entities. Here are the primary attributes you can use inside the @ManyToMany annotation:
  • targetEntity

  • cascade

  • fetch

  • mappedBy

Here’s a classic example to illustrate the usage of @ManyToMany:

Imagine we have User and Project entities, where multiple users can be assigned to multiple projects, and vice-versa :

Hibernate JPA Annotations

In the example, there’s a many-to-many relationship between User and Project. A joining table (user_project) is introduced to maintain this relationship, with @JoinTable used to define the table and its columns. The User entity is the "owning" side in this case (because it doesn't use the mappedBy attribute), while the Project entity is the "non-owning" side. Let’s deep dive into the behavior and significance of the user_project table in a many-to-many relationship between User and Project.

1. What is the user_project table?

• In a relational database, we cannot directly represent a many-to-many relationship between two tables. Therefore, we use an intermediary table, often called a “join table” or “junction table”, to achieve this. In this case, user_project is that intermediary table.
• The user_project table contains foreign keys to both the User and Project tables, effectively linking records from these two tables.

2. Ownership of the table:

• While the User and Project entities are clearly defined with their own attributes in the database, the user_project table is purely for maintaining relationships.
• The “ownership” in the context of JPA/Hibernate refers to which entity’s configuration determines the configuration of the join table and the relationship. In the provided example, the User entity is the "owning" side since it defines the @JoinTable and does not use the mappedBy attribute. Thus, changes to the relationship (like adding a new association between a user and a project) should ideally be managed through the User entity for consistency and to avoid unexpected behavior.

3. Behavior of the user_project table:

• Insert: When a new relationship is added between a User and a Project, a new row is inserted into the user_project table with the respective foreign keys of the User and Project.
• Update: The user_project table does not typically undergo "updates" in the traditional sense since its sole purpose is to link User and Project. However, the state of relationships can change, meaning rows can be added or removed, but individual rows are not modified.
• Delete: If a relationship between a User and a Project is removed, the corresponding row in the user_project table will be deleted. Depending on the cascade configuration, removing an entity (either a User or a Project) can also result in rows being removed from the user_project table.

4. Cascade Behavior:
• If the relationship is configured with CascadeType.REMOVE or CascadeType.ALL, removing a User (from the owning side) will remove all its associated relationships in the user_project table. The same applies to the Project side if it's configured with cascading deletes.
• Cascading doesn’t mean that if a User is deleted, all related Projects will be deleted, or vice versa. Instead, only the associations in the user_project table are removed.

5. Fetching and Lazy Loading:

• Depending on the fetch type configuration (FetchType.LAZY or FetchType.EAGER), when you fetch a User or Project entity, Hibernate might immediately load its relationships (EAGER) or wait until you specifically request them (LAZY).

In summary, the user_project table serves as a bridge between the User and Project entities, maintaining their many-to-many relationship. Its behavior and structure are determined by the annotations and configurations in the owning entity (User in the provided example). The table itself is simple, containing just foreign keys to the associated entities, but it's crucial for representing many-to-many relationships in relational databases. Choosing appropriate cascading options, fetch type, and handling the “owning” side correctly is crucial to ensure that the relationship is set up properly and efficiently.

Author
Lahiru Chandika