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!

Categories

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

Comments

Developed and designed by Netgloo
© 2016 Netgloo