• Skip to primary navigation
  • Skip to content
  • Skip to primary sidebar

Thoughts on Java

  • Tutorials ▼
    • Hibernate & JPA Tutorials
    • Hibernate Tips
    • Tutorials on YouTube
  • Books & Training ▼
    • Hibernate Tips Book
    • Online Training
    • On-Site Training
  • Consulting ▼
    • Consulting Call
    • Project Coaching
  • About ▼
    • About Thoughts on Java
    • Support Thoughts on Java
    • Resources
  • Member Library
You are here: Home / Hibernate / Hibernate Tips / Hibernate Tips: How to Customize a Constructor Expression for Different Subclasses
Special thanks to all Thoughts on Java Supporters for supporting this article!

Hibernate Tips: How to Customize a Constructor Expression for Different Subclasses

By Thorben Janssen Leave a Comment

  • tweet 
  • share 
  • share 
  • share 
  • share 
  • share 
  • e-mail 


Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question for a future Hibernate Tip, please post a comment below.

 

Question:

Last week, one of my coaching clients asked an interesting question:

He used the InheritanceType.SINGLE_TABLE to map an inheritance hierarchy to one database table. In one of his queries, he wanted to return the same DTO projection for different subentities of the hierarchy. Depending on the subentity class, he wanted to initialize different properties of the DTO object.

The question was: How do you implement a query that adapts the constructor call to different subentities?

 

Solution:

To be honest, the definition of the query was more complex than I expected. I first thought that I just needed to implement 2 different constructors and then use a CASE expression with JPQL‘s TYPE function to distinguish between the 2 subclasses.

But unfortunately, the combination of CASE expression, TYPE function, and constructor expression caused a strange error message with Hibernate 5.4.

In the end, I had to implement one constructor with parameters for all properties of the DTO and use a CASE expression for each property that wasn’t mapped by the superclass.

Let’s take a look at a simplified example, as I obviously can’t share any client’s code.

 

Entities and DTO

I created a small inheritance hierarchy consisting of a Publication as the superclass and the subclasses Book and BlogPost.

And I will use the PublicationPresentationValue class as the projection of my query. As you can see in the diagram, the constructor expects 4 parameters with the values for the id, title, numPages and url properties. Id and title are mapped by the Publication entity and will be set for all PublicationPresentationValue objects. The numPages property is specific for Book entities and will be null for all BlogPosts. The url property will only be set for publications of type BlogPost.

 

Subentity-specific constructor calls in JPQL

As I explained at the beginning of this Hibernate Tip, the combination of CASE expression, TYPE function, and constructor expression didn’t work with Hibernate 5.4. I had to use a constructor with parameters for all properties of the DTO instead. You can see the query here.

TypedQuery<PublicationPresentationValue> q = em.createQuery(
	"SELECT new org.thoughts.on.java.model.PublicationPresentationValue(p.id, p.title, "
		+ "CASE TYPE(p) WHEN Book THEN TREAT(p as Book).numPages ELSE NULL END , "
		+ "CASE TYPE(p) WHEN BlogPost THEN TREAT(p as BlogPost).url ELSE NULL END )"
	+ "FROM Author a JOIN a.publications p WHERE a.id = :id", PublicationPresentationValue.class);
q.setParameter("id", 1L);
List<PublicationPresentationValue> values = q.getResultList();

The query starts with a simple constructor expression that tells Hibernate to instantiate a PublicationPresentationValue object for each record. The interesting parts are the following lines of the query.

Line 2 starts with a CASE expression that I use to determine the 3rd constructor parameter. A CASE expression is similar to an if clause in Java. It evaluates a when_clause, which in this query is TYPE(p). The TYPE function returns the type of the selected entity. In this example, that’s either a Book or a BlogPost. If it’s a Book, I call the TREAT function to cast p to a Book entity and reference the numPages attribute. BlogPost entities don’t have a numPages attribute, and I return null instead.

Line 3 is very similar to the previous one. This time, I either want to return the url attribute of a BlogPost entity or null, if it’s a Book entity. So, I again use the TYPE function to get the class of the current entity and the TREAT function to cast it to a BlogPost entity.

As you can see, even so, JPQL is not as powerful as SQL, it still enables you to create quite complex queries. If you run this query and activate the SQL statement logging, you can see that Hibernate generates the following SQL statement.

18:55:20,810 DEBUG [org.hibernate.SQL] - 
    select
        publicatio2_.id as col_0_0_,
        publicatio2_.title as col_1_0_,
        case publicatio2_.DTYPE 
            when 'Book' then publicatio2_.numPages 
            else null 
        end as col_2_0_,
        case publicatio2_.DTYPE 
            when 'BlogPost' then publicatio2_.url 
            else null 
        end as col_3_0_ 
    from
        Author author0_ 
    inner join
        PublicationAuthor publicatio1_ 
            on author0_.id=publicatio1_.authorId 
    inner join
        Publication publicatio2_ 
            on publicatio1_.publicationId=publicatio2_.id 
            and publicatio2_.DTYPE in (
                'Book',
            'BlogPost') 
        where
            author0_.id=?

Get this Hibernate Tip as a printable PDF!

Join the free Thoughts on Java Library to get access to lots of member-only content, like a printable PDF for this post, lots of cheat sheets and 2 ebooks about Hibernate.
Join Now!

Already a member? Login here.

Learn more:

If you liked this article, you might also be interested in:

  • Ultimate Guide to JPQL Queries with JPA and Hibernate
  • Hibernate Tips: How to downcast entities in JPQL queries
  • Why, When and How to Use DTO Projections with JPA and Hibernate
  • Entities or DTOs &#8211; When should you use which projection?
 

Hibernate Tips Book


Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.

It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching and statically and dynamically defined queries.

Get it now as a paperback, ebook or PDF.
  • tweet 
  • share 
  • share 
  • share 
  • share 
  • share 
  • e-mail 
Become a Thoughts on Java Supporter to claim your member perks and to help me write more articles like this.

Filed Under: Hibernate Tips

Implement Your Persistence Layer with Ease

Learn More About Hibernate

Need Some Help with Your Project?

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Join over 10.000 developers
in the
Thoughts on Java Library

Ebooks Sidebar Get free access to ebooks, cheat sheets and training videos.
Join Now!
Don't like ads?
Become a Thoughts on Java Supporter.
Special Launch Price

Let’s Connect


Thorben Janssen
Independent consultant, trainer and author
  • Facebook
  • GitHub
  • Google+
  • LinkedIn
  • Twitter
  • xing
  • YouTube

Speaking at

7th February 2019
JUG Ostfalen (Germany):
Hibernate Tips 'n' Tricks: Typische Probleme schnell gelöst (Talk - German)

19th March 2019
JavaLand 2019 (Germany):
Hibernate Tips 'n' Tricks: Typische Probleme schnell gelöst (Talk - German)

21st March 2019
JavaLand 2019 (Germany):
Hibernate + jOOQ + Flyway = Die besten Frameworks in einem Stack (1-day Workshop - German)

6th-10th May 2019
JAX 2019 (Germany):
Hibernate Workshop: Komplexe Lösungen jenseits von CRUD (2-day Workshop - German)

6th-10th May 2019
JAX 2019 (Germany):
Spring Data JDBC vs. Spring Data JPA – Wer macht das Rennen? (Talk - German)

6th-10th May 2019
JAX 2019 (Germany):
Microservices mit Hibernate – typische Probleme und Lösungen (Talk - German)

Looking for an on-site training?

Featured Post

14 YouTube Channels You Should Follow in 2019

Getting Started With Hibernate

Entities or DTOs – When should you use which projection?

Ultimate Guide – Association Mappings with JPA and Hibernate

Ultimate Guide to JPQL Queries with JPA and Hibernate

Recent Posts

  • Hibernate Tips: How to Customize a Constructor Expression for Different Subclasses
  • Hibernate Tips: How to Map java.time.Year with JPA and Hibernate
  • Why, When and How to Use DTO Projections with JPA and Hibernate
  • Hibernate Tip: Map a bidirectional one-to-one association with shared composite primary key
  • Implementing the Repository pattern with JPA and Hibernate
  • Hibernate Tips: How to Handle NULL Values while Ordering Query Results in a CriteriaQuery
  • 6 Hibernate Best Practices for Readable and Maintainable Code
  • Can you use Hibernate/EclipseLink/JPA for your microservice?
  • 14 YouTube Channels You Should Follow in 2019
  • Hibernate Tips: How To Map an Entity to a Query
Don't like ads?
Become a Thoughts on Java Supporter.

Copyright © 2019 Thoughts on Java

  • Impressum
  • Disclaimer
  • Privacy Policy