Best way of handling entities inheritance in Spring Data JPA

38,544

I used the solution also described in this post from Netgloo's blog.

The idea is to create a generic repository class like the following:

@NoRepositoryBean
public interface ABaseRepository<T extends A> 
extends CrudRepository<T, Long> {
  // All methods in this repository will be available in the ARepository,
  // in the BRepository and in the CRepository.
  // ...
}

then I can write the three repositories in this way:

@Transactional
public interface ARepository extends ABaseRepository<A> { /* ... */ }

@Transactional
public interface BRepository extends ABaseRepository<B> { /* ... */ }

@Transactional
public interface CRepository extends ABaseRepository<C> { /* ... */ }

Moreover, to obtain a read-only repository for ARepository I can define the ABaseRepository as read-only:

@NoRepositoryBean
public interface ABaseRepository<T> 
extends Repository<T, Long> {
  T findOne(Long id);
  Iterable<T> findAll();
  Iterable<T> findAll(Sort sort);
  Page<T> findAll(Pageable pageable);
}

and from BRepository extend also the Spring Data JPA's CrudRepository to achieve a read/write repository:

@Transactional
public interface BRepository 
extends ABaseRepository<B>, CrudRepository<B, Long> 
{ /* ... */ }
Share:
38,544
Andrea
Author by

Andrea

Updated on July 16, 2022

Comments

  • Andrea
    Andrea almost 2 years

    I've three JPA entity classes A, B and C with the following hierarchy:

        A
        |
    +---+---+
    |       |
    C       B
    

    That is:

    @Entity
    @Inheritance
    public abstract class A { /* ... */ }
    
    @Entity
    public class B extends A { /* ... */ }
    
    @Entity
    public class C extends A { /* ... */ }
    

    Using Spring Data JPA, what is the best way to write repositories classes for such entities?

    I know that I can write these:

    public interface ARespository extends CrudRepository<A, Long> { }
    
    public interface BRespository extends CrudRepository<B, Long> { }
    
    public interface CRespository extends CrudRepository<C, Long> { }
    

    but if in the class A there is a field name and I add this method in the ARepository:

    public A findByName(String name);
    

    I've to write such method also in the other two repositories, and this is a bit annoying.. Is there a better way to handle such situation?

    Another point I would like to have is that ARespository should be a read-only repository (i.e. extend the Repository class) while the other two repositories should expose all the CRUD operations.

    Let me know possible solutions.

  • ALM
    ALM almost 8 years
    In this example can you use use repository B to set attributes belonging to Class A that is extended by Class B? I wanted to use a system like this to update B via a spring-data-rest controller.
  • Andrea
    Andrea almost 8 years
    @ALM I'm pretty sure you can do it. Did you tried it?
  • ALM
    ALM almost 8 years
    Yes I am about to try right now. I am actually debating how I want to set it up but I think I will create a very simple test first then run that to see. I read the other article and after that I believe it should inherit what is for repository A and then be able to be used by B. A would also be setup as read-only
  • Soumitri Pattnaik
    Soumitri Pattnaik over 4 years
    @ALM did you find a proper solution? I am also having a similar case where I want the child class repos for writes and the parent class repo just for reads such as GET ALL (including child entities). I also want to do it the way spring-data-rest does it, is there a way?