Spring Data JPA

この記事では、Spring Dataの使用について説明します。



Spring Dataは、データベースエンティティとやり取りし、リポジトリで整理し、データを取得し、変更するための追加の便利なメカニズムです。場合によっては、実装せずにインターフェイスとメソッドを宣言するだけで十分です。



内容:



  1. Springリポジトリ
  2. メソッド名からメソッドをリクエストする
  3. 構成とセットアップ
  4. 特別なパラメーター処理
  5. カスタムリポジトリの実装
  6. カスタムベースリポジトリ
  7. クエリメソッド- クエリ




1. Springリポジトリ



Spring Dataの基本概念はリポジトリです。 これらは、JPAエンティティを使用して対話するいくつかのインターフェイスです。 たとえば、インターフェース

public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID>





データの検索、保存、削除の基本操作を提供します(CRUD操作)



 T save(T entity); Optional findById(ID primaryKey); void delete(T entity);
      
      





およびその他の操作。



PagingAndSortingRepositoryなどの他の抽象化があります。



つまり インターフェイスが提供するリストがエンティティと対話するのに十分な場合、エンティティのベースインターフェイスを直接展開し、クエリメソッドで補完して操作を実行できます。 ここで、最も単純な場合に必要な手順を簡単に示します(構成、ORM、データベースに気を取られることはありません)。



1.エンティティを作成する



 @Entity @Table(name = "EMPLOYEES") public class Employees { private Long employeeId; private String firstName; private String lastName; private String email; // . . .
      
      





2. CrudRepositoryなど、Spring Dataインターフェースの1つから継承



 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>
      
      





3.データ操作用の新しいインターフェイスをクライアント(サービス)で使用する



 @Service public class EmployeesDataService { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Transactional public void testEmployeesCrudRepository() { Optional<Employees> employeesOptional = employeesCrudRepository.findById(127L); //.... }
      
      





ここでは、既製のfindByIdメソッドを使用しました。 つまり 実装することなく、迅速かつ簡単に、CrudRepositoryから既製の操作のリストを取得します。



  S save(S var1); Iterable<S> saveAll(Iterable<S> var1); Optional<T> findById(ID var1); boolean existsById(ID var1); Iterable<T> findAll(); Iterable<T> findAllById(Iterable<ID> var1); long count(); void deleteById(ID var1); void delete(T var1); void deleteAll(Iterable<? extends T> var1); void deleteAll();
      
      





このリストはエンティティと対話するのに十分でない可能性が高いことは明らかであり、ここで追加のクエリメソッドを使用してインターフェイスを拡張できます。



2.メソッド名からメソッドをクエリする



エンティティへのリクエストは、メソッド名から直接作成できます。 これを行うには、find ... By、read ... By、query ... By、count ... By、およびget ... Byプレフィックスが使用され、メソッドプレフィックスから離れて、残りの解析が開始されます。 導入文には、たとえばDistinctなどの追加の表現を含めることができます。 次に、最初のByはセパレーターとして機能し、実際の基準の開始を示します。 エンティティプロパティの条件を定義し、AndおよびOrを使用してそれらを結合できます。 例



 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { //    firstName And LastName Optional<Employees> findByFirstNameAndLastName(String firstName, String lastName); //   5  FirstName       FirstName List<Employees> findFirst5ByFirstNameStartsWithOrderByFirstName(String firstNameStartsWith);
      
      





ドキュメントでは、リスト全体と、メソッドを記述するためのルールを定義しています。 結果は、エンティティT、オプション、リスト、ストリームになります。 Ideaなどの開発環境では、クエリメソッドを記述するためのヒントがあります。



画像

実装なしでこの方法でメソッドを定義するだけで十分であり、Springはエンティティに対するリクエストを準備します。



 @SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testFindByFirstNameAndLastName() { Optional<Employees> employeesOptional = employeesCrudRepository.findByFirstNameAndLastName("Alex", "Ivanov");
      
      





3.構成とセットアップ



プロジェクト全体はgithubで利用可能です

github DemoSpringData



ここでは、いくつかの機能についてのみ触れます。



TransactionManager、dataSource、およびentityManagerFactory Beanは、context.xmlで定義されます。 その中に示すことも重要です



 <jpa:repositories base-package="com.example.demoSpringData.repositories"/>
      
      





リポジトリが定義されているパス。



EntityManagerFactoryはHibernate ORMと連携するように構成されており、Oracle XEデータベースと連携しています。ここでは、context.xmlで他のオプションを使用できます。 pomファイルにはすべての依存関係があります。



4.パラメーターの特別な処理



クエリメソッドのパラメーターでは、特別なパラメーターPageable、Sort、およびTopとFirstの制限を使用できます。



たとえば、次のように、2番目のページ(インデックスが-0)、3つの要素のサイズ、firstNameで並べ替え、リポジトリメソッドでPageableパラメーターを指定した後、メソッド名の基準も使用されます-「%



 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long> { List<Employees> findByFirstNameStartsWith(String firstNameStartsWith, Pageable page); //.... } //   @Test @Transactional public void testFindByFirstNameStartsWithOrderByFirstNamePage() { List<Employees> list = employeesCrudRepository .findByFirstNameStartsWith("A", PageRequest.of(1,3, Sort.by("firstName"))); list.forEach(e -> System.out.println(e.getFirstName() + " " +e.getLastName())); }
      
      





5.リポジトリのカスタム実装



リポジトリにメソッドの名前で記述できないメソッドが必要であると仮定し、インターフェースと実装クラスを使用して実装できます。 以下の例では、最高賃金の従業員を取得する方法をリポジトリに追加します。



インターフェースの宣言



 public interface CustomizedEmployees<T> { List<T> getEmployeesMaxSalary(); }
      
      





インターフェイスを実装します。 HQL(SQL)を使用すると、最高賃金の従業員が得られます。他の実装も可能です。



 public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Override public List getEmployeesMaxSalary() { return em.createQuery("from Employees where salary = (select max(salary) from Employees )", Employees.class) .getResultList(); } }
      
      





また、CustomedEmployeesを使用してCrud Repositoryの従業員を拡大します。



 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees>
      
      





ここには重要な機能が1つあります。 インターフェイスを実装するクラスは、 Implで終了するか(後置)、または後置を配置する必要がある構成で終了する必要があります



 <repositories base-package="com.repository" repository-impl-postfix="MyPostfix" />
      
      





リポジトリを介してこのメ​​ソッドの動作を確認する



 public class DemoSpringDataApplicationTests { @Autowired private CustomizedEmployeesCrudRepository employeesCrudRepository; @Test @Transactional public void testMaxSalaryEmployees() { List<Employees> employees = employeesCrudRepository.getEmployeesMaxSalary(); employees.stream() .forEach(e -> System.out.println(e.getFirstName() + " " + e.getLastName() + " " + e.getSalary())); }
      
      





CrudRepositoryでの削除など、Springインターフェースで既存のメソッドの動作を変更する必要がある別のケースでは 、データベースから削除する代わりに、削除のサインを設定する必要があります。 テクニックはまったく同じです。 以下に例を示します。



 public interface CustomizedEmployees<T> { void delete(T entity); // ... } //  CustomizedEmployees public class CustomizedEmployeesImpl implements CustomizedEmployees { @PersistenceContext private EntityManager em; @Transactional @Override public void delete(Object entity) { Employees employees = (Employees) entity; employees.setDeleted(true); em.persist(employees); }
      
      





employeesCrudRepositoryでdeleteを呼び出すと、オブジェクトは削除済みとしてのみマークされます。



6.ユーザーベースリポジトリ



前の例では、Crudでエンティティの削除リポジトリを再定義する方法を示しましたが、すべてのプロジェクトエンティティに対してこれを行う必要がある場合は、それぞれのインターフェイスがあまり良くないようにします...そしてSpringデータでは、ベースリポジトリを構成できます。 これを行うには:

インターフェイスが宣言され、その中でオーバーライドするためのメソッド(またはすべてのプロジェクトエンティティに共通)が宣言されます。 ここでは、すべてのエンティティに対して、 BaseEntityインターフェイスを導入しました(これは必須ではありません)。共通メソッドを呼び出すために、そのメソッドはエンティティのメソッドと一致しています。



 public interface BaseEntity { Boolean getDeleted(); void setDeleted(Boolean deleted); } //  Employees @Entity @Table(name = "EMPLOYEES") public class Employees implements BaseEntity { private Boolean deleted; @Override public Boolean getDeleted() { return deleted; } @Override public void setDeleted(Boolean deleted) { this.deleted = deleted; } //    @NoRepositoryBean public interface BaseRepository <T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID> { void delete(T entity); } //    BaseRepository public class BaseRepositoryImpl <T extends BaseEntity, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> { private final EntityManager entityManager; public BaseRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); this.entityManager = entityManager; } @Transactional @Override public void delete(BaseEntity entity) { entity.setDeleted(true); entityManager.persist(entity); } }
      
      





構成では、このベースリポジトリを指定する必要があります。これはすべてのプロジェクトリポジトリに共通です。



  <jpa:repositories base-package="com.example.demoSpringData.repositories" base-class="com.example.demoSpringData.BaseRepositoryImpl"/>
      
      





ここで、Employees Repository(およびその他)をBaseRepositoryから展開し、既にクライアントで使用する必要があります。



 public interface EmployeesBaseRepository extends BaseRepository <Employees, Long> { // ... }
      
      





EmployeesBaseRepositoryの確認



 public class DemoSpringDataApplicationTests { @Resource private EmployeesBaseRepository employeesBaseRepository; @Test @Transactional @Commit public void testBaseRepository() { Employees employees = new Employees(); employees.setLastName("Ivanov"); // Query by Example (QBE) Example<Employees> example = Example.of(employees); Optional<Employees> employeesOptional = employeesBaseRepository.findOne(example); employeesOptional.ifPresent(employeesBaseRepository::delete); }
      
      





これで、以前と同様に、オブジェクトは削除済みとしてマークされ、これはBaseRepositoryインターフェイスを拡張するすべてのエンティティに対して実行されます。 例では、検索方法- 例による照会(QBE)が適用されました。ここでは説明しません。例では、簡単で便利な機能を示します。



7.クエリメソッド- クエリ



以前に、メソッド名を使用して説明できない特定のメソッドまたはその実装が必要な場合、カスタマイズされたインターフェイス(CustomizedEmployees)を介してこれを実行し、計算実装を行うことができると書きました。 また、クエリ(HQLまたはSQL)、この関数の計算方法を示すことで、他の方法を使用できます。

getEmployeesMaxSalaryを使用した私の例では、この実装オプションはさらに単純です。 給与入力パラメーターで複雑にします。 つまり インターフェースで計算方法とリクエストを宣言するだけで十分です。



 @Repository public interface CustomizedEmployeesCrudRepository extends CrudRepository<Employees, Long>, CustomizedEmployees<Employees> { @Query("select e from Employees e where e.salary > :salary") List<Employees> findEmployeesWithMoreThanSalary(@Param("salary") Long salary, Sort sort); // ... }
      
      





確認中



 @Test @Transactional public void testFindEmployeesWithMoreThanSalary() { List<Employees> employees = employeesCrudRepository.findEmployeesWithMoreThanSalary(10000L, Sort.by("lastName"));
      
      





変更リクエストが存在する可能性があることに言及します。これには、追加の@Modifyingアノテーションが追加されます



 @Modifying @Query("update Employees e set e.firstName = ?1 where e.employeeId = ?2") int setFirstnameFor(String firstName, String employeeId);
      
      





クエリアノテーションのもう1つの優れた機能は、テンプレート#{#entityName}を使用して 、SpEL式を通じてエンティティドメインタイプをクエリに置き換えることです。



したがって、たとえば、私の仮想的な例では、すべてのエンティティに「削除済み」の記号が必要な場合、「削除済み」または「アクティブ」の記号が付いたオブジェクトのリストを取得する方法で基本インターフェースを作成します



 @NoRepositoryBean public interface ParentEntityRepository<T> extends Repository<T, Long> { @Query("select t from #{#entityName} t where t.deleted = ?1") List<T> findMarked(Boolean deleted); }
      
      





さらに、エンティティのすべてのリポジトリを拡張できます。 リポジトリではないが、「ベースパッケージ」構成フォルダにあるインターフェイスは、@ NoRepositoryBeanに注釈を付けます。



従業員リポジトリ



 @Repository public interface EmployeesEntityRepository extends ParentEntityRepository <Employees> { }
      
      





リクエストが実行されると、エンティティTの名前が、ParentEntityRepositoryを拡張する特定のリポジトリ(この場合はEmployees)のリクエスト本文に置き換えられます。



確認する



 @SpringBootTest public class DemoSpringDataApplicationTests { @Autowired private EmployeesEntityRepository employeesEntityRepository; @Test @Transactional public void testEntityName() { List<Employees> employeesMarked = employeesEntityRepository.findMarked(true); // ...
      
      





素材

Spring Data JPA-リファレンスドキュメント

githubのプロジェクト



All Articles