Handling entities inheritance with Spring Data JPA
Suppose to have three JPA entities, say User
, Person
and Company
, where the last two extends (inherits by) the first one:
User | +-----+-----+ | | Person Company
that is:
@Entity
@Inheritance
public abstract class User {
@Id
private long id;
@NotNull
private String email;
// ...
}
@Entity
public class Person extends User { /* ... */ }
@Entity
public class Company extends User { /* ... */ }
We want to write three Repository classes (aka DAO), one for each entity, following the hierarchy structure so all repository’s methods referring the base class User
(for example a method findByEmail
) are available on all repositories but written only once.
So, we start writing a generic user repository class:
@NoRepositoryBean
public interface UserBaseRepository<T extends User>
extends CrudRepository<T, Long> {
public T findByEmail(String email);
}
All methods in this repository will be available in the UserRepository
, in the PersonRepository
and in the CompanyRepository
.
Then we define repositories for the three entities:
@Transactional
public interface UserRepository extends UserBaseRepository<User> { /* ... */ }
@Transactional
public interface PersonRepository extends UserBaseRepository<Person> { /* ... */ }
@Transactional
public interface CompanyRepository extends UserBaseRepository<Company> { /* ... */ }
That’s all!
Some Tips
Referring the right entity type in the base repository
In the base repository you can referring the actual entity type inside a custom query (@Query
annotation) using the #{#entityName}
SpEL variable, for example:
public interface UserBaseRepository
extends CrudRepository<T, Long> {
@Query("select u from #{#entityName} as u where u.email = ?1 ")
T findByEmail(String email);
}
The value of #{#entityName}
will be the entity type T
.
Read-only repository for User class
To obtain a read-only repository for the User
class we can define the UserBaseRepository
as read-only:
@NoRepositoryBean
public interface UserBaseRepository<T>
extends Repository<T, Long> {
T findOne(Long id);
Iterable<T> findAll();
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
}
and from PersonRepository
(and CompanyRepository
) extend also the Spring Data JPA’s CrudRepository
to achieve a read/write repository:
@Transactional
public interface PersonRepository
extends UserBaseRepository<B>, CrudRepository<B, Long>
{ /* ... */ }
Try yourself
Get a working example using the code described above from our GitHub repository here:
https://github.com/netgloo/spring-boot-samples/tree/master/spring-boot-springdatajpa-inheritance
References
https://spring.io/blog/2011/07/27/fine-tuning-spring-data-repositories
http://docs.spring.io/spring-data/jpa/docs/current/reference/html
-
mrts
-
Augusto Santos
-
Andrea
-
-
Данил Ходырев
-
Andrea
-
-
Vishal Wagh
-
Armando Suárez Pons
-
Roland
-
Roland
-
-
Daniele Palladino
-
suman biswas
-
Achraf Smlali