How to map a PostgreSQL HStore entity property with JPA and Hibernate
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Hypersistence Optimizer is that tool!
Introduction
The open-source hibernate-types
project allows you to map a great variety of database types that are not supported natively by Hibernate ORM (e.g. JSON, ARRAY, YearMonth
, Month
, INET addresses).
In this article, we are going to see how you can map a PostgreSQL HStore type, which allows you to store key/value pairs, to a Java Map
entity property when using JPA and Hibernate.
How to map a PostgreSQL HStore entity property with JPA and #Hibernate . @vlad_mihalcea https://t.co/360MtHSYmw pic.twitter.com/KcXP3PD6lO
— Java (@java) January 5, 2019
Maven dependency
First of all, you need to set up the following Maven dependency in your project pom.xml
configuration file:
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
If you’re using older versions of Hibernate (e.g. 5.1 or 4.3), check out the hibernate-types
GitHub repository for more info about the matching dependency for your current Hibernate version.
Domain Model
First of all, we need to make sure we have the hstore
extension installed in our database:
CREATE EXTENSION IF NOT EXISTS hstore;
Our application needs to store Book
entities in the following database table:
Notice that the properties
column type is hstore
which is not supported by Hibernate ORM.
To map the PostgreSQL hstore
column types to a Java Map
, you need a custom Hibernate type since the built-in types don’t support persisting database-specific types. Luckily, thanks to the hibernate-types
library you can easily map the book
table to the following Book
entity:
@Entity(name = "Book") @Table(name = "book") @TypeDef(name = "hstore", typeClass = PostgreSQLHStoreType.class) public class Book { @Id @GeneratedValue private Long id; @NaturalId @Column(length = 15) private String isbn; @Type(type = "hstore") @Column(columnDefinition = "hstore") private Map<String, String> properties = new HashMap<>(); //Getters and setters omitted for brevity }
The @TypeDef
annotation is used to register the PostgreSQLHStoreType
custom Hibernate Type with the hstore
name. Afterward, the properties
entity attribute uses the @Type
annotation to specify that the hstore
Hibernate Type should be used to handle this entity attribute.
Testing Time
Now, when storing the following Book
entity:
Book book = new Book(); book.setIsbn("978-9730228236"); book.getProperties().put("title", "High-Performance Java Persistence"); book.getProperties().put("author", "Vlad Mihalcea"); book.getProperties().put("publisher", "Amazon"); book.getProperties().put("price", "$44.95"); entityManager.persist(book);
Hibernate executes the following SQL INSERT statement:
INSERT INTO book (isbn, properties, id) VALUES ( '978-9730228236', '"author"=>"Vlad Mihalcea", "price"=>"$44.95", "publisher"=>"Amazon", "title"=>"High-Performance Java Persistence"', 1 )
And, when we fetch the Book
entity, we can see that all properties are fetched properly.
Book book = entityManager .unwrap(Session.class) .bySimpleNaturalId(Book.class) .load("978-9730228236"); assertEquals( "High-Performance Java Persistence", book.getProperties().get("title") ); assertEquals( "Vlad Mihalcea", book.getProperties().get("author") );
Awesome, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
The hibernate-types
project supports more than hstore
PostgreSQL type. You can map PostgreSQL-specific Enums, nullable Character
, JSON, or even provide your own immutable Hibernate custom Types
.
For more details about the hibernate-types
project, check out this article.
