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

    Thanks for sharing!

  • Augusto Santos

    Thanks, it’s a perfect tutorial. I have a question. Can I replace CrudRepository by JpaRepository in the UserBaseRepository class? What’s the difference between them?

Categories

Category BootstrapCategory CoffeescriptCategory DrupalCategory GravCategory HTMLCategory JavascriptCategory JoomlaCategory jQueryCategory LaravelCategory MagentoCategory PHPCategory SharePointCategory SpringCategory ThymeleafCategory WordPressCategory Workflow

Comments

Developed and designed by Netgloo
© 2017 Netgloo