How to quickly create JPA Queries for nested properties

How to quickly create JPA Queries for nested properties

March 25, 2024
Spring, Spring Data JPA
JPA Queries, Repository Concept, Normalisation

Sometimes we may need to define some of entity’s fields and properties as embedded classes or records.

As the information is still persisted at the entity level, there may be a need to query data using this embedded information.

So how to quickly define a corresponding query method in a Spring Data JPA Repository?

Example #

Let’s take the following example:

public class SomeEntity {
    private String someField;
    @Embedded
    private SomeValueObject someEmbeddedField;
    ...
}
@Embeddable
record SomeValueObject {
    private boolean someNestedFilterFlag;
}

We want to filter all SomeEntity objects using the embedded filter someNestedFilterFlag.

Solution #

If we try to define the query as follow:

public interface SomeEntityRepository extends JpaRepository<SomeEntity, String> {
    List<SomeEntity> findAllBySomeNestedFilterFlag();
}

We get this error at the server startup:

Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List org.example.SomeEntityRepository.findAllBySomeNestedFilterFlag(); No property 'someNestedFilterFlag' found for type 'SomeEntity'
        at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:106) ~[spring-data-jpa-3.2.2.jar:3.2.2]
...

That it because at the class level the field is still part of a different object, even if the persistence table is the same.

What if we try:

  List<SomeEntity> findAllBySomeEmbeddedField_someNestedFilterFlag()

?

Here we get a different error!

Caused by: java.lang.IllegalStateException: Method public abstract java.util.List org.example.SomeRepository.findAllBySomeEmbeddedField_someNestedFilterFlag() expects at least 1 arguments but only found 0; This leaves an operator of type SIMPLE_PROPERTY for property someEmbeddedField.someNestedFilterFlag unbound

That is because we defined a filter query without any input! In this particular case we are asking to filter by someNestedFilterFlag without providing any filter value.

Spring Data JPA Provides a list of query keywords to use in order to provide such filter values.

Here we need to append IsTrue filter value to the method’s name:

public interface SomeEntityRepository extends JpaRepository<SomeEntity, String> {
   List<SomeEntity> findAllBySomeEmbeddedField_someNestedFilterFlagIsTrue()
}

Spring Data JPA - Query property expressions

Spring Data JPA - Query keywords