How to map calculated properties with Hibernate @Generated annotation

(Last Updated On: January 29, 2018)
Imagine having a tool that can automatically detect if you are using JPA and Hibernate properly. Hypersistence Optimizer is that tool!


As I explained in this previous article, you can map calculated properties using Hibernate @Formula, and the value is generated at query time.

In this post, you’ll see how you can calculate an entity property at INSERT or UPDATE time.

Domain Model

Assuming we have the following Hero entity mapping:

@Entity(name = "Hero")
public class Hero {

    private Long id;

    private String firstName;

    private String lastName;

    private String middleName1;

    private String middleName2;

    private String middleName3;

    private String middleName4;

    private String middleName5;

    @Generated( value = GenerationTime.ALWAYS )
    @Column(columnDefinition =
        "AS CONCAT(" +
        "	COALESCE(firstName, ''), " +
        "	COALESCE(' ' + middleName1, ''), " +
        "	COALESCE(' ' + middleName2, ''), " +
        "	COALESCE(' ' + middleName3, ''), " +
        "	COALESCE(' ' + middleName4, ''), " +
        "	COALESCE(' ' + middleName5, ''), " +
        "	COALESCE(' ' + lastName, '') " +
    private String fullName;

    //Getters and setters omitted for brevity

    public String getFullName() {
        return fullName;

The fullName property is calculated using the SQL Server CONCAT function, by including all names. The COALESCE function is used because CONCAT does not take a separator in SQL Server.

The columnDefinition is only useful when generating the database schema from JPA annotations (which you shouldn’t do in a production environment). Because we provided a custom @Column definition, the underlying database table looks like this:

  firstName VARCHAR(255) ,
  fullName AS CONCAT(COALESCE(firstName, ''),
                     COALESCE(' ' + middleName1, ''),
                     COALESCE(' ' + middleName2, ''),
                     COALESCE(' ' + middleName3, ''),
                     COALESCE(' ' + middleName4, ''),
                     COALESCE(' ' + middleName5, ''),
                     COALESCE(' ' + lastName, '')) ,
  lastName VARCHAR(255) ,
  middleName1 VARCHAR(255) ,
  middleName2 VARCHAR(255) ,
  middleName3 VARCHAR(255) ,
  middleName4 VARCHAR(255) ,
  middleName5 VARCHAR(255) ,
  PRIMARY KEY ( id )

The @Generated annotation is used to instruct Hibernate when the associated column value is calculated, and it can take two values:

  • INSERT – meaning that the column value is calculated at insert time
  • ALWAYS – meaning that the column value is calculated both at insert and update time

Testing time

Now, when saving a Hero entity:

doInJPA( entityManager -> {
    Hero heroine = new Hero();
    heroine.setId( 1L );

    heroine.setFirstName( "Agustina" );
    heroine.setMiddleName1( "Raimunda" );
    heroine.setMiddleName2( "María" );
    heroine.setMiddleName3( "Saragossa" );
    heroine.setLastName( "Domènech" );

    entityManager.persist( heroine );"After entity persist action");

        "Agustina Raimunda María Saragossa Domènech", 
} );

Hibernate generates the following SQL statements:

-- After entity persist action

    (firstName, lastName, middleName1, middleName2, middleName3, middleName4, middleName5, id) 
    ('Agustina', 'Domènech', 'Raimunda', 'María', 'Saragossa', NULL(VARCHAR), NULL(VARCHAR), 1)

    h.fullName as fullName3_0_ 
FROM Hero h 

Note the SELECT query that is issued after the flush operation, which allows Hibernate to fetch the calculated entity property.

When updating and loading the entity:

doInJPA( entityManager -> {
    Hero heroine = entityManager.find( Hero.class, 1L );
    heroine.setMiddleName1( null );
    heroine.setMiddleName2( null );
    heroine.setMiddleName3( null );
    heroine.setLastName( "de Aragón" );"After entity update action");

    assertEquals("Agustina de Aragón", heroine.getFullName());
} );

Hibernate generates the following SQL statements:

SELECT AS id1_0_0_,
    h.firstName AS firstNam2_0_0_,
    h.fullName AS fullName3_0_0_,
    h.lastName AS lastName4_0_0_,
    h.middleName1 AS middleNa5_0_0_,
    h.middleName2 AS middleNa6_0_0_,
    h.middleName3 AS middleNa7_0_0_,
    h.middleName4 AS middleNa8_0_0_,
    h.middleName5 AS middleNa9_0_0_
FROM Hero h

    firstName = 'Agustina', 
    lastName = 'de Aragón', 
    middleName1 = NULL(VARCHAR), 
    middleName2 = NULL(VARCHAR), 
    middleName3 = NULL(VARCHAR), 
    middleName4 = NULL(VARCHAR), 
    middleName5 = NULL(VARCHAR) 
    id = 1 

-- After entity update action

    h.fullName as fullName3_0_ 
FROM Hero h 

Again, the last SELECT query is used to ensure that the managed entity is in sync with the underlying table row.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.


Mapping calculated entity properties is fairly easy with Hibernate, and you have multiple ways to achieve this goal.

Download free ebook sample

Newsletter logo
10 000 readers have found this blog worth following!

If you subscribe to my newsletter, you'll get:
  • A free sample of my Video Course about running Integration tests at warp-speed using Docker and tmpfs
  • 3 chapters from my book, High-Performance Java Persistence,
  • a 10% discount coupon for my book.

Leave a 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.

Want to run your data access layer at warp speed?