Hibernate Basics(Part3)

Dev_RV
10 min readMar 21, 2024

--

What is association mapping & querying mechanism in Hibernate ?

Implementation of One to one mapping using below examples ,mapping between customer & locker class.

The foreign key column (LOCKERID) of the CUSTOMER table references the primary key column of the LOCKER table, so the Customer entity can be the source and the Locker entity can be the target. To map the foreign key column, source entity must be associated with the target entity i.e. the Customer class has a reference of Locker.

The annotations used in Customer class (source) for one to one mapping with Locker (target) are:

@OneToOne(cascade = CascadeType.ALL)

This annotation is applied to the reference attribute of Locker in the Customer entity which indicates that the relationship has one to one cardinality. The cascade attribute of the annotation is mandatory. This attribute transfers operation (such as insert, update, delete) done on the Customer object to its Locker object.

@JoinColumn(name = “lockerId”, unique = true)

The annotation has two attributes, name attribute specifies the name of the foreign key column in the Customer table and the unique attribute assures unique values in the foreign key column to achieve one to one mapping.

Example —

Customer.java

import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = “CUSTOMER”)
public class Customer {
@Id
private int customerId;
private String customerName;
private Date dateOfBirth;
private String address;
private long phoneNo;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = “lockerId”, unique = true)
private Locker locker;

public Customer(int customerId, String customerName, Date dateOfBirth, String address, long phoneNo) {
super();
this.customerId = customerId;
this.customerName = customerName;
this.dateOfBirth = dateOfBirth;
this.address = address;
this.phoneNo = phoneNo;
}

public Customer() {
super();
}

public int getCustomerId() {
return customerId;
}

public void setCustomerId(int customerId) {
this.customerId = customerId;
}

public String getCustomerName() {
return customerName;
}

public void setCustomerName(String customerName) {
this.customerName = customerName;
}

public Date getDateOfBirth() {
return dateOfBirth;
}

public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public long getPhoneNo() {
return phoneNo;
}

public void setPhoneNo(long phoneNo) {
this.phoneNo = phoneNo;
}

public Locker getLocker() {
return locker;
}

public void setLocker(Locker locker) {
this.locker = locker;
}
}

Locker.java

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = “locker”)
public class Locker {
@Id
private String lockerId;
private String lockerType;
private Double rent;

public Locker() {
super();
}

public Locker(String lockerId, String lockerType, Double rent) {
super();
this.lockerId = lockerId;
this.lockerType = lockerType;
this.rent = rent;
}
public String getLockerId() {
return lockerId;
}
public void setLockerId(String lockerId) {
this.lockerId = lockerId;
}
public String getLockerType() {
return lockerType;
}
public void setLockerType(String lockerType) {
this.lockerType = lockerType;
}
public Double getRent() {
return rent;
}
public void setRent(Double rent) {
this.rent = rent;
}
}

Some of the possible CRUD operations which can be performed on the associated entities (Customer.java and Locker.java) are given below:

Persisting source and target entity instances together — Adding a new customer with the details of the new locker allocated.

Persisting only source entity instance — Adding a new customer without any locker details.

Associating an existing source entity instance with a new target entity instance — Allocating a new locker to an existing customer.

Fetching source and target entity instances together — Retrieving the details of a customer along with the corresponding locker details (if available).

Removing an existing source entity instance along with the associated target entity instance — Deleting the details of an existing customer and the allocated locker details from the database tables.

Removing only the source entity instance — Deleting the details of a customer while retaining the corresponding locker details.

Hibernate provides different ways to query the data.

Retrieval by Identifier

In this approach, get() or load() method of Session API is used for retrieving the data. The data retrieval can be done, only by using the primary key.

Hibernate Native SQL Query

Native SQL is SQL in the native format of the database that you are connected to. Hibernate supports the running of SQL query directly using this feature. All operations like create, update, delete and select can be performed using this.

Hibernate Query Language

HQL is an object-oriented query language which is similar to SQL. HQL operates on persistent objects and their properties and not on tables and columns of the database. Hence data can be retrieved based on non-key properties.

Criteria API

Criteria API allows to build up a criteria query object programmatically using which filtration rules and logical conditions can be applied.

_____________________________________________________________

For working with Hibernate queries knowledge on SQLQuery API and Query API is required.

SQLQuery API:

SQLQuery API is used to work with Native SQL Query mechanism. This is available in org.hibernate package. An SQLQuery instance is created by calling createSQLQuery() method of session API. Using this instance you can pass the query as a string.

This API gets data from the selected database table using list().

Query API:

Query API works with HQL. This is available in org.hibernate package. A Query instance is obtained by calling createQuery() of Session API.

This API contains the following methods and these can be used to retrieve values from the Query instance

list(): Returns the list of objects retrieved by the query.

executeUpdate(): Executes a data manipulation statement in the database.

uniqueResult(): Returns one unique object.

Native SQL is SQL in the native format, of the database you are connected to, for performing operations like create, update, delete and select.

To work with Native SQL Query mechanism:

  • Use createSQLQuery() method of session Object to pass the query string.
  • It returns an org.hibernate.SQLQuery object.
  • Invoke the list() to get the data from the selected database table

As Hibernate supports running SQL query, migration from JDBC to Hibernate can be achieved easily. However, there are certain advantage of Native SQL Query Mechanism has:

  • It might cause portability issues.
  • No Object Oriented feature is used.

Running Native SQL queries from Hibernate definitely defeats the purpose of ORM.

Hibernate provides HQL which follows the Object-Oriented paradigm and fulfills ORM specification.

  • HQL is very similar to SQL but can be written in fewer words.
  • Helps to retrieve data based on non-key properties.
  • Applied on persistent objects and their attributes.
  • Offers efficient caching and SQL generation strategies.
  • Portable as it does not deal with database tables and columns directly.
  • HQL uses class name and properties instead of table name and column.
  • Understands Object Oriented concepts like — inheritance, polymorphism, association, aggregation, and composition.

Supports writing of queries using:

Selection: from, as

Associations and joins: inner join, outer join, right outer join, full join

Projection: select

Constraints: where

Other constructs: aggregate functions, expressions, order by clauses, group by clauses, polymorphic selections, sub-queries.

Hibernate ORM provides HQL which has the Query language syntax but understands Object Oriented Paradigm.

To work with HQL :

  • use createQuery() method of Session Object to pass the query string.
  • It returns an org.hibernate.Query object.
  • Following methods can be used to retrieve values from the Query instance:
  • list(): Returns the list of objects retrieved by the query
  • executeUpdate(): Executes a data manipulation statement in the database
  • uniqueResult(): Returns one unique object.

Now the same requirement of retrieving details of customers whose age is more than 50 can be implemented using “HQL” as shown below:

Consider a scenario for retrieving multiple Attributes (customerId and customerName) value from the Customer Entity where customerId is 1002 or greater.

Hibernate provides a solution to SQL injection attacks by allowing the user to construct the queries dynamically at runtime using parameters binding technique. If required, the compiled query can be reused with different parameters, which results in increased performance. Hibernate supports two ways for parameter binding or parameter setting.

Positioned Parameter: It uses a question mark (?) to define a named parameter in the query, and according to the position sequence, the value is set to the parameter.

Named Parameter(Preferred mostly): It uses a colon, for example :id to define a named parameter in the query.

When an application uses the same query at many places it’s really tiresome to manage and write the same query again and again. It is an overhead for the application to compile and create the execution plan of the same query again and again. Hibernate ORM gives a solution for this problem in the form of “Named Query”.

  • Named queries allow managing queries, used repeatedly.
  • The query is maintained along with the entity instance.
  • Compiled and kept ready with the execution plan.
  • Named queries are defined at the entity level using @NamedQuery.
  • There can be one or more named queries defined using @NamedQueries.

HQL like SQL, allows all the standard aggregate functions supported by SQL. In HQL, aggregate functions can be used on the entity instances or persistent fields thereby taking care of ORM aspects. Aggregate functions help to compute results using the attribute values available in the database.

Aggregate functions supported by Hibernate:

  • avg()
  • max()
  • min()
  • sum()
  • count()
  • count(*)

While using aggregate functions following points are worth remembering:

  • The queries return a unique result.
  • The result should be type casted to the proper data type.

HQL Functions

JOIN is a strategy to retrieve data by linking between two associated entities.

Join is of Two types: Implicit and Explicit.

Implicit Join

Explicit Join: JOIN keyword is shown explicitly. Type of JOIN strategies supported by Hibernate:

  • JOIN or INNER JOIN
  • OUTER JOIN
  • LEFT OUTER JOIN
  • RIGHT OUTER JOIN

Challenges using HQL —

  • Too many constructs: HQL provides too many options to write a query.
  • Hard to debug errors: The errors are hard to debug since error detection happens at runtime.
  • Hard to maintain if complexity increases: As the complexity of queries increases, HQL becomes difficult to maintain.

Updates in hibernates —

In Hibernate 5.0 you don’t need any additional annotations or converter to persist the classes of the Date and Time API. You can use them in the same way as any other supported attribute types.No @Temporal in Hibernate 5

Hibernate 5.1 introduced a new MultiIdentifierLoadAccess interface which provides a comfortable option to load multiple entities with one query. You just need to call the byMultipleIds() method on the Hibernate Session to get a MultiIdentifierLoadAccess interface and provide a list of primary key values to the multiLoad() method.

Since Hibernate 5.2, @NamedQuery and a lot of other Hibernate annotations are now repeatable and can be assigned multiple times.

The new stream() method of Hibernate’s Query interface fetches the result set in multiple batches and uses Hibernate’s ScrollableResults implementation to scroll through it. This is a great fit if you use a Stream to process the result set records one by one and helps you to implement your use case efficiently.

Now hibernate supports the joining of unassociated entities in a query. For example, you can use the INNER JOIN in the createQuery() function. Hibernate will process the createQuery() and generate the necessary JDBC query to fetch the results.

Hibernate 5 supportsObject/Grid Mapper (OGM) and through this, you can use Hibernate to persist data into NoSQL databases.

Hibernate 5 comes with great search features that are very easy now.

Hibernate 5 comes with a new Bootstrap API which improves performance and helps in better integration.

You can use the Hibernate 5 without persistence.xml through new bootstrap API. Hibernate JPA environment can be configured programmatically in runtime.

Apart from all these changes, more changes include JMS controller API changed and ServiceRegistry API updated and there are many classes that have been renamed or re-located to another package.

Thus while making sort you have to change SortField.STRING to SortField.Type.STRING.

For Hibernates Advance Topics ->>> https://medium.com/@dev_RV/hibernate-advance-389fbf1b4ebb

--

--

Dev_RV

Knows about DSA , Java , Springboot , Microservices