web-dev-qa-db-ja.com

Spring Data JPAでエンティティの継承を処理する最良の方法

私は3つのJPAエンティティクラスABおよびCを次の階層で持っています:

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

あれは:

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

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

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

Spring Data JPAを使用して、リポジトリこのようなエンティティのクラスを記述する最良の方法は何ですか?

私はこれらを書くことができることを知っています:

public interface ARespository extends CrudRepository<A, Long> { }

public interface BRespository extends CrudRepository<B, Long> { }

public interface CRespository extends CrudRepository<C, Long> { }

クラスAにフィールドnameがあり、ARepositoryにこのメソッドを追加する場合:

public A findByName(String name);

私は他の2つのリポジトリにもこのようなメソッドを記述しなければなりませんが、これは少し面倒です。そのような状況に対処するより良い方法はありますか?

もう1つのポイントは、ARespositoryを読み取り専用リポジトリにする(つまり、Repositoryクラスを拡張する)一方で、他の2つのリポジトリはすべてのCRUD操作を公開する必要があるということです。

可能な解決策を教えてください。

42
Andrea

Netglooのブログの この投稿 でも説明されているソリューションを使用しました。

考え方は、次のようなgenericリポジトリクラスを作成することです。

@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.
  // ...
}

次に、この方法で3つのリポジトリを作成できます。

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

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

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

さらに、ARepositoryの読み取り専用リポジトリを取得するには、ABaseRepositoryを読み取り専用として定義できます。

@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);
}

また、BRepositoryからSpring Data JPAのCrudRepositoryも拡張して、読み取り/書き込みリポジトリを実現します。

@Transactional
public interface BRepository 
extends ABaseRepository<B>, CrudRepository<B, Long> 
{ /* ... */ }
53
Andrea