Hibernate Tips: Cache preprocessed, non-persistent attributes


Take your skills to the next level!

The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.


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 you like me to answer, please leave a comment below.

Question:

I often need to provide a value that gets calculated based on an entity attribute, like the age of a person. How can I cache this calculated attribute in the entity without storing it in the database?

Solution:

There are different ways to provide a calculated value to the user of the entity:

  1. You can use a @Formula to provide an SQL expression which returns the value.
  2. You can use field access and calculate the value in a getter method.
  3. You can use a transient entity attribute which stores calculated value without persisting it in the database.

I already explained option 1 in a previous post and will, therefore, focus on option 2 and 3.

Calculate in a getter method

Option 2 is easy to implement. When you use field access, you can add additional getter methods to your entity. You can for example, add a getAge() method that calculates and returns the age of the Author.

This approach requires you to calculate the value for each call of the getAget() method and is, therefore, not a good solution for complex calculations.

@Entity
public class Author {

	…

	@Column
	private LocalDate dateOfBirth;

	public int getAge() {
		return return Period.between(dateOfBirth, LocalDate.now()).getYears();
	}
}

Transient entity attributes

The transient attribute approach requires a little more code but allows you to store the calculated value in an entity attribute without persisting it. The @Transient annotation tells Hibernate, and any other JPA implementation, to ignore the attribute when writing or reading the entity. You can, therefore, use it in your getAge() method to store the calculation result after it was calculated. This can be useful, if you need to perform a complex calculation that you don’t want to repeat for each call.

@Entity
public class Author {

	…

	@Column
	private LocalDate dateOfBirth;

	@Transient
	private Integer age;

	…

	public int getAge() {
		if (this.age == null) {
			this.age = Period.between(dateOfBirth, LocalDate.now()).getYears();
		}

		return age;
	}
}

Learn more

You can also use @ColumnTransformer and AttributeConverter if you want to replace the presentation of an attribute.

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!

4 Comments

  1. Trying to use option 3 with object that is query-cached. It seems that each time the object is retrieved, a new object (different object ID) is generated so the transient field has to be recomputed. My computation is expensive. Is there anyway to have the query cache deliver the same object rather than creating a new one?

    1. Avatar photo Thorben Janssen says:

      No, you can’t avoid that.
      Hibernate stores entities in the dehydrated form (only attribute values, no entity instance) always instantiates a new entity object.

  2. Avatar photo Guillermo González de Agüero says:

    Better than calculating on the getter method, I prefer to use a @PostLoad to do this kind of computation, leaving my getters clean.

    1. Avatar photo Thorben Janssen says:

      That’s also an option. But you need to be aware, that the value will not be available for newly created entities. It depends on the use case, if that’s an issues or not.

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.