Spring Data Composable Repository

Spring Data Composableリポジトリ

1. 前書き

実際のシステムまたはプロセスをモデル化する場合、ドメイン駆動設計(DDD)スタイルのリポジトリが適切なオプションです。 このまさに目的のために、Spring Data JPAをデータアクセス抽象化レイヤーとして使用できます。

この概念に慣れていない場合は、this introductory tutorialをチェックしてスピードを上げてください。

このチュートリアルでは、フラグメントと呼ばれる小さなリポジトリを使用して作成されるカスタムリポジトリと構成可能なリポジトリを作成するという概念に焦点を当てます。

2. Mavenの依存関係

構成可能なリポジトリを作成するオプションは、Spring 5以降で使用できます。

Spring DataJPAに必要な依存関係を追加しましょう。


    org.springframework.data
    spring-data-jpa
    2.0.9.RELEASE

また、データアクセス層が機能するためには、データソースを設定する必要があります。 開発と迅速なテストのためにset up an in-memory database like H2を使用することをお勧めします。

3. バックグラウンド

3.1. JPA実装としてのHibernate

Spring Data JPAは、デフォルトでJPA実装としてHibernateを使用します。 一方を他方と簡単に混同したり、比較したりできますが、目的は異なります。

Spring Data JPAはデータアクセス抽象化レイヤーであり、その下で任意の実装を使用できます。 たとえば、switch out Hibernate in favor of EclipseLinkを使用できます。

3.2. デフォルトのリポジトリ

多くの場合、自分でクエリを作成する必要はありません。

代わりに、ジェネリックSpringデータリポジトリインターフェースを拡張するインターフェースを作成するだけです。

public interface LocationRepository extends JpaRepository {
}

そして、これ自体で、タイプLongの主キーを持つLocationオブジェクトに対して、CRUD、ページング、並べ替えなどの一般的な操作を実行できるようになります。

さらに、Spring Data JPAには、メソッド名の規則を使用してクエリを生成する機能を提供するクエリビルダーメカニズムが装備されています。

public interface StoreRepository extends JpaRepository {
    List findStoreByLocationId(Long locationId);
}

3.3. カスタムリポジトリ

必要に応じて、フラグメントインターフェイスを記述し、必要な機能を実装することで、enrich our model repositoryを実行できます。 これは、独自のJPAリポジトリに挿入できます。

たとえば、ここでは、フラグメントリポジトリを拡張することで、ItemTypeRepositoryを充実させています。

public interface ItemTypeRepository
  extends JpaRepository, CustomItemTypeRepository {
}

ここで、CustomItemTypeRepositoryは別のインターフェースです。

public interface CustomItemTypeRepository {
    void deleteCustomById(ItemType entity);
}

その実装は、JPAだけでなく、あらゆる種類のリポジトリにすることができます。

public class CustomItemTypeRepositoryImpl implements CustomItemTypeRepository {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void deleteCustomById(ItemType itemType) {
        entityManager.remove(itemType);
    }
}

接尾辞Implが付いていることを確認する必要があります。 ただし、次のXML構成を使用してカスタムの接尾辞を設定できます。

またはこの注釈を使用して:

@EnableJpaRepositories(
  basePackages = "com.example.repository", repositoryImplementationPostfix = "CustomImpl")

4. 複数のフラグメントを使用したリポジトリの作成

数リリース前までは、単一のカスタム実装を使用してのみリポジトリインターフェイスを拡張できました。 これは制限でした。そのため、関連するすべての機能を1つのオブジェクトにまとめる必要がありました。

言うまでもなく、複雑なドメインモデルを持つ大規模なプロジェクトでは、クラスが肥大化します。

Spring 5では、enrich our JPA repository with multiple fragment repositoriesのオプションがあります。 繰り返しますが、これらのフラグメントがインターフェイスと実装のペアとして存在するという要件が残っています。

これを示すために、2つのフラグメントを作成しましょう。

public interface CustomItemTypeRepository {
    void deleteCustom(ItemType entity);
    void findThenDelete(Long id);
}

public interface CustomItemRepository {
    Item findItemById(Long id);
    void deleteCustom(Item entity);
    void findThenDelete(Long id);
}

もちろん、それらの実装を作成する必要があります。 ただし、独自のJPAリポジトリにこれらのカスタムリポジトリを(関連する機能とともに)プラグインする代わりに、単一のJPAリポジトリの機能を拡張できます。

public interface ItemTypeRepository
  extends JpaRepository, CustomItemTypeRepository, CustomItemRepository {
}

これで、リンクされたすべての機能が1つのリポジトリにまとめられました。

5. あいまいさへの対処

複数のリポジトリから継承しているため、衝突が発生した場合にどの実装を使用するかを判断するのが難しい場合があります。 たとえば、この例では、両方のフラグメントリポジトリに、同じ署名を持つメソッドfindThenDelete()があります。

このシナリオでは、the order of the declaration of the interfaces is used to resolve the ambiguityです。 したがって、この場合、最初に宣言されているため、CustomItemTypeRepository内のメソッドが使用されます。

このテストケースを使用して、これをテストできます。

@Test
public void givenItemAndItemTypeWhenDeleteThenItemTypeDeleted() {
    Optional itemType = composedRepository.findById(1L);
    assertTrue(itemType.isPresent());

    Item item = composedRepository.findItemById(2L);
    assertNotNull(item);

    composedRepository.findThenDelete(1L);
    Optional sameItemType = composedRepository.findById(1L);
    assertFalse(sameItemType.isPresent());

    Item sameItem = composedRepository.findItemById(2L);
    assertNotNull(sameItem);
}

6. 結論

この記事では、Spring Data JPAリポジトリーを使用するさまざまな方法を検討しました。 Springを使用すると、多くのコードやSQLクエリを記述しなくても、ドメインオブジェクトでデータベース操作を簡単に実行できることがわかりました。

このサポートは、構成可能なリポジトリを使用してかなりカスタマイズできます。

この記事のコードスニペットは、Maven project here on Githubとして入手できます。