I recently switched from JEE to Spring Boot and I'm loving it so far. But I have run into a little issue. I have this method that fetches lazy references that used to look something like this:
public Foo getParentWithChildren(long id, boolean isFetchChild, boolean isFetchPets) {
StringBuilder sql = new StringBuilder();
sql.append("select DISTINCT(p) from Parent p");
if(isFetchChild) {
sql.append(" left join p.child c");
} if(isFetchPets) {
sql.append(" left join p.pets pts");
}
sql.append(" where p.id=:id");
TypedQuery<Foo> query = em.createQuery(sql.toString(), Foo.class);
query.setParameter("id", id);
return query.getSingleResult();
}
Now with spring data and their awesome interfaces I would like to do something simlar using the @Query annotation on the interface instead of having to write a custom implementation. But is it possible to do something similar using only the interface.
The example below will obviously not work but I hope you understand what I am trying to acchieve
@Query("select distinct(p) from Parent p " +
(fetchChild ? " left join p.child c" : "") +
(fetchPets ? " left join p.pets pts" : "") +
" where p.id=:id")
Foo getParentWithChildren(@Param("id") long id, @Param("fetchChild") boolean isFetchChild, @Param("fetchPets") boolean isFetchPets);
I something similar possible?
You can create multiple methods in your interface and use the EntityGraph functionality introduced in JPA 2.1 which Spring Data JPA supports in various ways:
http://docs.spring.io/spring-data/jpa/docs/1.11.0.RELEASE/reference/html/#jpa.entity-graph
public interface FooRepository extends JpaRepository<Foo, Long>{
@EntityGraph(attributePaths = { "children" })
@Query("select f from Foo f where f.id = :id")
Foo getFooWithChildren(@Param("id") long id);
@EntityGraph(attributePaths = { "pets" })
@Query("select f from Foo f where f.id = :id")
Foo getFooWithPets(@Param("id") long id);
@EntityGraph(attributePaths = { "children", "pets" })
@Query("select f from Foo f where f.id = :id")
Foo getFooWithChildrenAndPets(@Param("id") long id);
}
One issue with this is you need to repeat the Query for each method. Being able to pass in the entity graphs as parameters to a query method would seem to be useful functionality missing from the Spring Data JPA module.
I raised at ticket for this some time ago but no update yet:
https://jira.spring.io/browse/DATAJPA-645?filter=-2
A link in an answer to this question Spring Data JPA And NamedEntityGraphs however suggests an extension at the below which allows us to do exactly this:
https://github.com/Cosium/spring-data-jpa-entity-graph
With this extension the code is simplified to:
public interface FooRepository extends JpaEntityGraphRepository<Foo, Long>{
}
and call it as:
Foo foo = fooRepository.findOne(1L,
new DynamicEntityGraph(Arrays.asList({"children");
Foo foo = fooRepository.findOne(1L,
new DynamicEntityGraph(Arrays.asList({"children", "pets"});