-
In addition to
spring-data-jpa
, add the library dependency :<dependency> <groupId>com.cosium.spring.data</groupId> <artifactId>spring-data-jpa-entity-graph</artifactId> <version>${spring-data-jpa-entity-graph.version}</version> </dependency>
-
In your Spring configuration, set the repository factory bean class to
EntityGraphJpaRepositoryFactoryBean
:@Configuration @EnableJpaRepositories(repositoryFactoryBeanClass = EntityGraphJpaRepositoryFactoryBean.class) public class DataRepositoryConfiguration { //... }
-
Make sure your repositories extend the Spring Data standard ones or the library provided repositories:
EntityGraphJpaRepository
which is equivalent to standardJpaRepository
EntityGraphJpaSpecificationExecutor
which is equivalent to standardJpaSpecificationExecutor
EntityGraphQuerydslPredicateExecutor
which is equivalent to standardQuerydslPredicateExecutor
EntityGraphCrudRepository
which is equivalent to standardCrudRepository
EntityGraphPagingAndSortingRepository
which is equivalent to standardPagingAndSortingRepository
EntityGraphQueryByExampleExecutor
which is equivalent to standardQueryByExampleExecutor
Let's consider the following entities and repository :
@Entity
public class Brand {
@Id
private long id = 0;
private String name;
//...
}
@NamedEntityGraphs(value = {
@NamedEntityGraph(name = "Product.brand", attributeNodes = {
@NamedAttributeNode("brand")
})
})
@Entity
public class Product {
@Id
private long id = 0;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Brand brand;
//...
}
public interface ProductRepository extends EntityGraphJpaRepository<Product, Long> {
List<Product> findByName(String name, EntityGraph entityGraph);
}
You can pass the entity graph to the findByName
method :
// This will apply 'Product.brand' named EntityGraph to findByName
productRepository.findByName("MyProduct", EntityGraphs.named("Product.brand"));
Or to the findOne
method :
// This will apply 'Product.brand' named EntityGraph to findOne
productRepository.findById(1L, EntityGraphs.named("Product.brand"));
Or any method you like.
You can also pass a dynamically built EntityGraph by using DynamicEntityGraph
, it's also accessible through a helper method:
productRepository.findById(1L, EntityGraphUtils.fromAttributePaths("brand", "maker"));
This is similar to Spring's ad-hoc attribute paths, and equivalent to writing this in your repository's interface:
@EntityGraph(attributePaths = { "brand", "maker" })
Product findById(Long id);
Composing entity graphs by hand can be tedious and error prone. Wouldn't it be great to benefit from autocompletion and strong type checking while composing your entity graph?
spring-data-jpa-entity-graph-generator
has you covered.
This annotation processor makes use of the JPA metamodel informations (part of JPA specification) generated by the tool
of your choice (e.g. hibernate-jpamodelgen
) to generate EntityGraph composers allowing you to safely and easily compose
EntityGraph at runtime.
You first need to add a JPA metamodel information generator. hibernate-jpamodelgen
is great and should be compatible with
any JPA ORM:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate.version}</version>
<scope>provided</scope>
</dependency>
Then add the entity graph generator annotation processor dependency:
<dependency>
<groupId>com.cosium.spring.data</groupId>
<artifactId>spring-data-jpa-entity-graph-generator</artifactId>
<version>${spring-data-jpa-entity-graph.version}</version>
<scope>provided</scope>
</dependency>
After compiling your project, you should find XEntityGraph
classes where X
is the name of your Entity. Thanks to
them, you will be able to build entity graphs like this:
// Let's build entity graph "product(brand, category, maker(country))"
EntityGraph entityGraph = ProductEntityGraph
.____()
.brand()
.____
.category()
.____
.maker()
.country()
.____
.____();
productRepository.findById(1L, entityGraph);
For an Entity, you can define its default EntityGraph.
An Entity default EntityGraph will be used each time the Entity repository method is called without EntityGraph.
A default EntityGraph name must end with .default
.
@NamedEntityGraphs(value = {
@NamedEntityGraph(name = "Product.default", attributeNodes = {
@NamedAttributeNode("brand")
})
})
@Entity
public class Product {
@Id
private long id = 0;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Brand brand;
//...
}
// This call will make use of "Product.default" EntityGraph.
productRepository.findById(1L);