How to map the latest child of a parent entity using Hibernate JoinFormula
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Hypersistence Optimizer is that tool!
Introduction
In this article, I’m going to explain how the Hibernate JoinFormula annotation works and how you can use it to map the latest child of a parent entity.
As previously explained, the @JoinFormula
is a very awesome annotation which allows you to customize the way you join entities beyond JPA @JoinColumn
capabilities.
Domain Model
For the upcoming test cases, we are going to use the following entities:
The PostComment
entity is mapped as follows:
@Entity(name = "PostComment") @Table(name = "post_comment") public class PostComment { @Id private Long id; @ManyToOne(fetch = FetchType.LAZY) private Post post; private String review; @Column(name = "created_on") @Temporal(TemporalType.TIMESTAMP) private Date createdOn; //Getters and setters omitted for brevity }
Not only the PostComment
has a @ManyToOne
association to a Post
, but the Post
is also associated with the latest PostComment
as follows:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id private Long id; private String title; @ManyToOne(fetch = FetchType.LAZY) @JoinFormula(""" (SELECT pc.id FROM post_comment pc WHERE pc.post_id = id ORDER BY pc.created_on DESC LIMIT 1) """ ) private PostComment latestComment; //Getters and setters omitted for brevity }
The latestComment
attribute associates the parent Post
entity with the latest PostComment
child entity. The @JoinFormula
annotation allows us to define any SQL select query to provide the relationship between two entities.
Testing the Hibernate JoinFormula annotation
Considering we have the following entities in our database:
Post post = new Post() .setId(1L) .setTitle("High-Performance Java Persistence"); entityManager.persist(post); assertNull(post.getLatestComment()); entityManager.persist( new PostComment() .setId(1L) .setPost(post) .setCreatedOn( Timestamp.valueOf( LocalDateTime.of(2016, 11, 2, 12, 33, 14) ) ) .setReview("Woohoo!") ); entityManager.persist( new PostComment() .setId(2L) .setPost(post) .setCreatedOn( Timestamp.valueOf( LocalDateTime.of(2016, 11, 2, 15, 45, 58) ) ) .setReview("Finally!") ); entityManager.persist( new PostComment() .setId(3L) .setPost(post) .setCreatedOn( Timestamp.valueOf( LocalDateTime.of(2017, 2, 16, 16, 10, 21) ) ) .setReview("Awesome!") );
When we fetch the Post
entity, we can see that the latestComment
attribute works as expected:
Post post = entityManager.find(Post.class, 1L); PostComment latestComment = post.getLatestComment(); assertEquals("Awesome!", latestComment.getReview());
Online Workshops
If you enjoyed this article, I bet you are going to love my upcoming Online Workshops.
- Transactions and Concurrency Control Patterns (3 hours) on the 10th of February
- High-Performance Java Persistence (16 hours) starting on the 1st of March in collaboration with Bouvet
Conclusion
As I explained in my book, High-Performance Java Persistence, if you don’t take advantage of the underlying JPA provider or relational database capabilities, you are going to lose lots of features.

The LIMIT 1 works for H2. I get syntax errors when running against Oracle or SQL Server. Is there a portable way, or do I have to switch for another solution?
Theoretically, you could use the SQL Standard
FETCH FIRST 1 ROWS ONLY
syntax. However, I tested it and it looks like Hibernate adds some aliases to the keyword as it doesn’t recognize them. Most likely they need to be added to the baseDialect
. You should open a Hibernate Jira issue for it.