Spring Data JPAおよびNullパラメータ

1. 概要

この記事では、https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa [Spring Data JPA]で_null_パラメーターを処理する方法を示します。
場合によっては、パラメータでレコードを検索するときに、フィールド値として_null_を含む行を検索する必要があります*。 また、_null_を無視して、クエリでそのフィールドをスキップすることもできます*。
以下に、これらのそれぞれを実装する方法を示します。

2. 簡単な例

_Customer_エンティティがあるとしましょう:
@Entity
public class Customer {

    @Id
    @GeneratedValue
    private long id;
    private String name;
    private String email;

    public Customer(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // getters/setters

}
また、JPAリポジトリがあります。
public interface CustomerRepository extends JpaRepository<Customer, Long> {

   // method1
   // method2
}
_name_と_email_で顧客を検索します。
この目的のために、_null_パラメーターを異なる方法で処理する2つのメソッドを作成します。

3. _Null_パラメータを処理する方法

まず、パラメーターの_null_値を_IS NULL_として解釈するメソッドを作成し、次に_null_パラメーターを無視してWHERE句から除外するメソッドを作成します。

* 3.1。 IS NULLクエリ*

最初の方法は、クエリメソッドの_null_パラメータがデフォルトで_IS NULL_として解釈されるため、作成が非常に簡単です。
メソッドを作成しましょう:
List<Customer> findByNameAndEmail(String name, String email);
_null_メールを渡すと、生成されたJPQLには_IS NULL_条件が含まれます。
customer0_.email is null
これを実証するために、テストを作成しましょう。
最初に、いくつかの顧客をリポジトリに追加します。
@Before
public void before() {
    entityManager.persist(new Customer("A", "[email protected]"));
    entityManager.persist(new Customer("D", null));
    entityManager.persist(new Customer("D", "[email protected]"));
}
_name_パラメーターの値として_“ D” _を、_email_パラメーターの値として_null_をクエリメソッドに渡します。 ちょうど1人の顧客が見つかることがわかります。
List<Customer> customers = repository.findByNameAndEmail("D", null);

assertEquals(1, customers.size());

Customer actual = customers.get(0);

assertEquals(null, actual.getEmail());
assertEquals("D", actual.getName());

* 3.2。 代替メソッドを使用した_null_パラメータの回避*

一部のパラメーターを無視し、対応するフィールドを_WHERE_句に含めない場合があります。
リポジトリにさらにクエリメソッドを追加できます。 たとえば、_email_を無視するには、_name_のみを受け入れるメソッドを追加できます。
 List<Customer> findByName(String name);
しかし、列の1つを無視するこのような方法は、すべての組み合わせを実現するために多くのメソッドを追加する必要があるため、数が増えるにつれて貧弱にスケーリングされました。

* 3.3。 _ @ Query_アノテーションを使用した_null_パラメーターの無視*

_ @ Query_アノテーションを使用し、JPQLステートメントに小さな複雑さを追加することにより、追加のメソッドの作成を回避できます。
@Query("SELECT c FROM Customer c WHERE (:name is null or c.name = :name) and (:email is null"
  + " or c.email = :email)")
List<Customer> findCustomerByNameAndEmail(@Param("name") String name, @Param("email") String email);
_email_パラメータが_null_の場合:
:email is null or s.email = :email
この場合、句は常に_true_であるため、_WHERE_句全体には影響しません。
これが機能することを確認しましょう:
List<Customer> customers = repository.findCustomerByNameAndEmail("D", null);

assertEquals(2, customers.size());
名前が_“ D” _である2人の顧客がメールを無視していることがわかりました。
生成されたJPQL WHERE句は次のようになります。
where (? is null or customer0_.name=?) and (? is null or customer0_.email=?)
この方法では、データベースサーバーに信頼を置き、クエリパラメータが_null_であることに関する句を認識し、クエリの実行計画を最適化して、パフォーマンスのオーバーヘッドが大きくならないようにします。 一部のクエリまたはデータベースサーバーでは、特に大規模なテーブルスキャンが関係するため、パフォーマンスのオーバーヘッドが発生する可能性があります。

4. 結論

Spring Data JPAがクエリメソッドの_null_パラメータをどのように解釈するかを示し、デフォルトの動作を変更する方法を示しました。
おそらく将来、https://jira.spring.io/browse/DATAJPA-209 [_ @ NullMeans_]アノテーションを使用して_null_パラメーターを解釈する方法を指定できるようになるでしょう。 この機能は現時点で提案されている機能であり、まだ検討中であることに注意してください。
要約すると、_null_パラメータを解釈する主な方法は2つあり、これらは両方とも提案された_ @​​ NullMeans_アノテーションによって提供されます。
  • IS(null)–セクション3.1で説明されているデフォルトのオプション。

  • IGNORED(_WHERE_句から_null_パラメーターを除外)–
    追加のクエリメソッド(セクション3.2。)または回避策(セクション3.3。)を使用して達成

    いつものように、完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-jpa-2[GitHub上]で入手できます。