Preamble
Hibernate is an open source ORM (Object Relational Mapping) library that helps programmers write Java applications that can map objects (pojo) with relational database management, and support implementation of programming concepts. object-oriented program with relational data. In short, Hibernate will be an intermediate layer between the application and the database, and we will communicate with Hibernate instead of communicating with the database. This article will not cover hibernate configurations but will show the benefits of hibernate that Java Developer itself does not know.
content
Use UUID as a primary key in Hibernate
Problem: You want to use the UUID as a primary key in the database.
Solution :
Hibernate has very good support for the properties of type java.util.UUID to use the UUID as the primary key and provides two generators for generating UUIDs. Hibernate supports 2 main types IETF RFC 4122 version 4 and IETF RFC 4122 version 1. Here I only introduce to create according to RFC 4122 standard version 4
ETF RFC 4122 version 4.
To be able to create UUDI, we just need to add the @GeneratedValue annotation to the java.util.UUID primary key attribute. For example
1 2 3 4 5 6 7 8 9 | @Entity public class Author { @Id @GeneratedValue @Column(name = "id", updatable = false, nullable = false) private UUID id; ... } |
When saving the object to the databae, a UUID will be created before the object is saved to the database
1 2 3 4 5 | Author a = new Author(); a.setFirstName("Trung"); a.setLastName("Tran"); em.persist(a); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 12:25:31,071 DEBUG [org.hibernate.event.internal.AbstractSaveEventListener] - Generated identifier: 35a18e65-97b9-48fd-a547-56f81e157253, using strategy: org.hibernate.id.UUIDGenerator 12:25:31,113 DEBUG [org.hibernate.SQL] - insert into Author (firstName, lastName, version, id) values (?, ?, ?, ?) 12:25:31,117 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [1] as [VARCHAR] - [Trung] 12:25:31,118 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [VARCHAR] - [Tran] 12:25:31,119 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [INTEGER] - [0] 12:25:31,120 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [4] as [OTHER] - [35a18e65-97b9-48fd-a547- 56f81e157253] |
Map enum to database column
Problem: You want to map the enum property to columns in the database.
Solution: JPA and Hibernate provide two standard options for mapping enum to the column database. You can use Enum as String or in order
- For Enum as String, renaming an enum value requires us to also update the database
- For ordinal type: The order of an enum value depends on its position in the enum declaration. You will have to update your database when you delete existing values or change the location of enum values. When performing the mapping, Hibernate and JPA support a comment so you can define the mapping type. with @Enumerated annotation
For example, a basic enum with an Enum is called AuthorStatus
1 2 3 4 | public enum AuthorStatus { PUBLISHED, SELF_PUBLISHED, NOT_PUBLISHED; } |
. For the example below, use the @Enumerated annotation with ordinal type. If the default @Enumerated annotation is not declared or EnumType is not specified, Hibernate will use the default ordinal as the default mapping.
1 2 3 4 5 6 7 | @Entity public class Author { @Enumerated(EnumType.ORDINAL) private AuthorStatus status; ... } |
When performing Author saving to database with PUBLISHED status, Hibernate will store the value 0 into the database
If using the type ** STRING **, we need to declare the @Enumerated annotation and define the mapping type as EnumType.STRING
1 2 3 4 5 6 | @Entity public class Author { @Enumerated(EnumType.STRING) private AuthorStatus status; } |
When Hibernate saves the Author into the database, Hibernate will save the PUBLISHED value to the database in the status column
Automatically set an attribute before saving
Problem : You want to automatically set an attribute before it is saved to the database: For example, time, calculating a value … Solution :: You can use the @PrePersist annotation to automatically set a price before it is saved in the database
1 2 3 4 5 6 7 8 9 10 | @Entity public class Author { ... @PrePersist private void initializeCreatedAt() { this.createdAt = LocalDateTime.now(); log.info("Set createdAt to "+this.createdAt); } } |
Hibernate will call this method before it saves the Author into the database.
1 2 3 4 5 | Author a = new Author(); a.setFirstName("Trung"); a.setLastName("Tran"); em.persist(a); |
Hibernate calls the initizeCreatedAt method before it selects the primary key value from the database. It will then save the createdAt value to the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 05:34:00,205 INFO [org.thoughts.on.java.model.Author] - Set createdAt to 2020-02-23T05:34:00.198 05:34:00,211 DEBUG [org.hibernate.SQL] - select nextval ('hibernate_sequence') 05:34:00,260 DEBUG [org.hibernate.SQL] - insert into Author (createdAt, firstName, lastName, version, id) values (?, ?, ?, ?, ?) 05:34:00,267 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [1] as [TIMESTAMP] - [2020-02-23T05:34:00.198] 05:34:00,269 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [2] as [VARCHAR] - [Trung] 05:34:00,270 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [3] as [VARCHAR] - [Tran] 05:34:00,271 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [4] as [INTEGER] - [0] 05:34:00,272 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] - binding parameter [5] as [BIGINT] - [1] |
Calculate the properties of an object with the @Formula annotation in hibernate
Problem : The value of one of the entity’s attributes needs to be calculated using the SQL expression. And you want to map it with hibernate.
Solution : The @Formula annotation can be used to declare values in the SQL snippet. Hibernate will execute it when performing queries from the database.
The following example uses the @Formula annotation to calculate the Author’s ages
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Entity public class Author { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", updatable = false, nullable = false) private Long id; @Column private LocalDate dateOfBirth; @Formula(value = "date_part('year', age(dateOfBirth))") private int age; ... public int getAge() { return age; } } |
When Hibernate fetches the Entity Author from the database, it adds the SQL excerpt of the @Formula annotation to its SQL statement.
1 2 3 4 5 6 | 05:35:15,762 DEBUG [org.hibernate.SQL] – select author0_.id as id1_0_, author0_.dateOfBirth as dateOfBi2_0_, author0_.firstName as firstNam3_0_, author0_.lastName as lastName4_0_, author0_.version as version5_0_, date_part(‘year’, age(author0_.dateOfBirth)) as formula0_ from Author author0_ where author0_.id=1 |
Query query results as Stream in Java 8
Problem : You want to use Java 8 Stream to access the results Solution : For Hibernate 5.2 version, we can do that by using: Hibernate’s Query interface. It returns query results as Stream and uses HibernateScrollableResults to access the results. For example :
1 2 3 4 5 6 | Stream<Book> books = session.createQuery("SELECT b FROM Book b", Book.class).stream(); books.map(b -> b.getTitle() + " was published on " + b.getPublishingDate()) forEach(m -> log.info(m)); |
Conclude
The above article is only a small part of the tips for you to work more effectively with Hibernate. There are many tricks I have not yet mentioned in this article. See you in the next posts