バネデータJPAを用いた複数カラム間のデータ検索
12899 ワード
このブログ記事は、春のデータJPAを使用して、テーブル内の複数の列のデータを検索する処理を説明します.
Spring Boot 2.4.X スプリングデータJPA 2.4.X 角11 .X MySQL バネデータJPAを使用してテーブル内の複数の列を横切ってデータを検索する方法は3つあります 例Matcherの使用 仕様の使用 クエリの使用
従業員とプロジェクトテーブルの例を挙げましょう.クリエイトビュー
matcherの例
プローブ:人口フィールドを持つドメインオブジェクトの実際の例. Examplematcher :特定のフィールドに一致する方法についての詳細を実行します.これは、複数の例間で再利用することができます. 以下に例を示します.クエリの作成に使用します.
ビルド
仕様
リポジトリをクローンする まず、Dockerの作成ファイルを使用してMySQLデータベースをオンラインで持参.これは、MySQLデータベースを開始し、Intelに基づいてデータを挿入するだけでなく、データベースを作成します.SQLファイル
Multi ColumnSearchSpringDataJapAppsクラスを実行して、スプリングブートアプリケーションを起動します 角度Webアプリケーションディレクトリに移動する
すべての依存関係をインストールする
角度アプリケーションを開始する
移動するhttp://localhost:4200 ブラウザでテーブルを確認します.
従業員プロジェクト あなたがどんなエラーを得るならば
正規のJPAメソッドを解決できない簡単なクエリについては 必須のマッチングとオプションのマッチングを必要とする他の任意の要件については 必須のマッチングと任意のマッチングを必要とする要件については、この記事に示すように、仕様(推奨)またはクエリを使用します. コードアップロードGithub 参考に
技術
従業員とプロジェクトテーブルの例を挙げましょう.クリエイトビュー
EmployeeProjectView
(データベースと同じemployee_project_view
) 従業員とプロジェクトテーブルを結合し、単一のビューでそれらを返すpackage com.pj.multicolumnsearch.domain;
import lombok.Data;
import org.springframework.data.annotation.Immutable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
* @author Pavan Jadda
*/
@Data
@Entity
@Immutable
@Table(name = "employee_project_view")
public class EmployeeProjectView implements Serializable
{
private static final long serialVersionUID = 1916548443504880237L;
@Id
@Column(name = "employee_id")
private Long employeeId;
@Column(name = "last_name")
private String lastName;
@Column(name = "first_name")
private String firstName;
@Column(name = "project_id")
private Long projectId;
@Column(name = "project_name")
private String projectName;
@Column(name = "project_budget")
private Double projectBudget;
@Column(name = "project_location")
private String projectLocation;
}
matcherの例
春の医者によると
Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation and does not require you to write queries that contain field names
クエリAPIでは、3つの部分から構成されます.
Query by Example (QBE) is a user-friendly querying technique with a simple interface. It allows dynamic query creation and does not require you to write queries that contain field names
@Override
public Page<EmployeeProjectView> findEmployeeProjectsExampleMatcher(EmployeeRequestDTO employeeRequestDTO)
{
/* Build Search object */
EmployeeProjectView employeeProjectView=new EmployeeProjectView();
employeeProjectView.setEmployeeId(employeeRequestDTO.getEmployeeId());
employeeProjectView.setLastName(employeeRequestDTO.getFilterText());
employeeProjectView.setFirstName(employeeRequestDTO.getFilterText());
try
{
employeeProjectView.setProjectId(Long.valueOf(employeeRequestDTO.getFilterText()));
employeeProjectView.setProjectBudget(Double.valueOf(employeeRequestDTO.getFilterText()));
}
catch (Exception e)
{
log.debug("Supplied filter text is not a Number");
}
employeeProjectView.setProjectName(employeeRequestDTO.getFilterText());
employeeProjectView.setProjectLocation(employeeRequestDTO.getFilterText());
/* Build Example and ExampleMatcher object */
ExampleMatcher customExampleMatcher = ExampleMatcher.matchingAny()
.withMatcher("firstName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
.withMatcher("lastName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
.withMatcher("projectId", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
.withMatcher("projectName", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
.withMatcher("projectLocation", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase())
.withMatcher("projectBudget", ExampleMatcher.GenericPropertyMatchers.contains().ignoreCase());
Example<EmployeeProjectView> employeeExample= Example.of(employeeProjectView, customExampleMatcher);
/* Get employees based on search criteria*/
return employeeProjectViewRepository.findAll(employeeExample, PageRequest.of(employeeRequestDTO.getCurrentPageNumber(),
employeeRequestDTO.getPageSize(), Sort.by(employeeRequestDTO.getSortColumnName()).descending()));
}
だから作ろうEmployeeProjectView
オブジェクトをコピーして、UIから受信した検索値を入力します.ビルド
ExampleMatcher
要求された値のいずれかに一致するようにSo let’s create EmployeeProjectView object and copy the user entered search values received from UI to it.
Then build ExampleMatcher to match any one of the requested values
ビルドExample
からExampleMatcher
Example<EmployeeProjectView> employeeExample= Example.of(employeeProjectView, customExampleMatcher);
次に、Example
従業員プロジェクトを探す/* Get employees based on search criteria*/
return employeeProjectViewRepository.findAll(employeeExample, PageRequest.of(employeeRequestDTO.getCurrentPageNumber(),
employeeRequestDTO.getPageSize(), Sort.by(employeeRequestDTO.getSortColumnName()).descending()));
仕様
春の医者によると
JPA Specification uses Criteria API to define and build queries programmatically. By writing a criteria, you define the where clause of a query for a domain class. To support specifications, you can extend your repository interface with the JpaSpecificationExecutor interface
public interface EmployeeRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor
{ }
仕様は、容易に結合されることができて、あらゆる必要な組合せのために質問(メソッド)を宣言する必要なしで
/**
* Builds and return specification object that filters data based on search string
*
* @param employeeRequestDTO Employee Projects Request DTO object
*
* @return Specification with Employee Id and Filter Text
*/
private Specification<EmployeeProjectView> getSpecification(EmployeeRequestDTO employeeRequestDTO)
{
//Build Specification with Employee Id and Filter Text
return (root, criteriaQuery, criteriaBuilder) ->
{
criteriaQuery.distinct(true);
//Predicate for Employee Id
Predicate predicateForEmployee = criteriaBuilder.equal(root.get("employeeId"), employeeRequestDTO.getEmployeeId());
if (isNotNullOrEmpty(employeeRequestDTO.getFilterText()))
{
//Predicate for Employee Projects data
Predicate predicateForData = criteriaBuilder.or(
criteriaBuilder.like(root.get("firstName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("lastName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectId").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectBudget").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectLocation"), "%" + employeeRequestDTO.getFilterText() + "%"));
//Combine both predicates
return criteriaBuilder.and(predicateForEmployee, predicateForData);
}
return criteriaBuilder.and(predicateForEmployee);
};
}
我々は、従業員IDとフィルタテキストを使用して述語を構築することができます.述語は、1つの義務的な条件と多くの任意の条件を指定することができます.この場合、従業員IDとそれから列の残りを一致するストリングと一致させる必要があります.
最初の最初の述語を作成する従業員のIDに一致する
Predicate predicateForEmployee = criteriaBuilder.equal( root.get("employeeId"), employeeRequestDTO.getEmployeeId());
次に、検索テキストを持つすべての列に一致するように
//Predicate for Employee Projects data
Predicate predicateForData = criteriaBuilder.or(
criteriaBuilder.like(root.get("firstName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("lastName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectId").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectBudget").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectLocation"), "%" + employeeRequestDTO.getFilterText() + "%"));
それから両方の述語を結合する
/** Combine both predicates */
return criteriaBuilder.and(predicateForEmployee, predicateForData);
を参照getSpecification()
メソッドemployeeProjectViewRepository.findAll()
方法
@Override
public Page<EmployeeProjectView> findEmployeeProjectsBySpecification(EmployeeRequestDTO employeeRequestDTO)
{
return employeeProjectViewRepository.findAll(getSpecification(employeeRequestDTO), PageRequest.of(employeeRequestDTO.getCurrentPageNumber(), employeeRequestDTO.getPageSize(),
Sort.by(isNotNullOrEmpty(employeeRequestDTO.getSortDirection()) ? Sort.Direction.fromString(employeeRequestDTO.getSortDirection()) : Sort.Direction.DESC, employeeRequestDTO.getSortColumnName())));
}
クエリ
マルチカラム検索を実装する最後の方法は@Query
注釈.
public interface EmployeeProjectViewRepository extends JpaRepository<EmployeeProjectView, Long>, JpaSpecificationExecutor<EmployeeProjectView>
{
@Query(value = "SELECT e FROM EmployeeProjectView as e WHERE e.employeeId=:employeeId and (:inputString is null or e.lastName like %:inputString% ) and " +
"(:inputString is null or e.firstName like %:inputString%) and (:inputString is null or concat(e.projectId,'') like %:inputString%) and " +
" (:inputString is null or e.projectName like %:inputString%) and (:inputString is null or concat(e.projectBudget,'') like %:inputString%) and "+
" (:inputString is null or e.projectLocation like %:inputString%)"
)
Page<EmployeeProjectView> findAllByInputString(Long employeeId, String inputString, Pageable pageable);
}
上記のように、クエリの注釈を使用してemployeeId
従業員IDと検索テキスト(InputString)パラメータをパラメータとして、列の残りを一致させます.時inputString
がNULLでない場合、すべてのカラムに対して比較され、結果が結合されます.
プロジェクトを実行する
JPA Specification uses Criteria API to define and build queries programmatically. By writing a criteria, you define the where clause of a query for a domain class. To support specifications, you can extend your repository interface with the JpaSpecificationExecutor interface
public interface EmployeeRepository extends CrudRepository<Customer, Long>, JpaSpecificationExecutor
{ }
/**
* Builds and return specification object that filters data based on search string
*
* @param employeeRequestDTO Employee Projects Request DTO object
*
* @return Specification with Employee Id and Filter Text
*/
private Specification<EmployeeProjectView> getSpecification(EmployeeRequestDTO employeeRequestDTO)
{
//Build Specification with Employee Id and Filter Text
return (root, criteriaQuery, criteriaBuilder) ->
{
criteriaQuery.distinct(true);
//Predicate for Employee Id
Predicate predicateForEmployee = criteriaBuilder.equal(root.get("employeeId"), employeeRequestDTO.getEmployeeId());
if (isNotNullOrEmpty(employeeRequestDTO.getFilterText()))
{
//Predicate for Employee Projects data
Predicate predicateForData = criteriaBuilder.or(
criteriaBuilder.like(root.get("firstName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("lastName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectId").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectBudget").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectLocation"), "%" + employeeRequestDTO.getFilterText() + "%"));
//Combine both predicates
return criteriaBuilder.and(predicateForEmployee, predicateForData);
}
return criteriaBuilder.and(predicateForEmployee);
};
}
Predicate predicateForEmployee = criteriaBuilder.equal( root.get("employeeId"), employeeRequestDTO.getEmployeeId());
//Predicate for Employee Projects data
Predicate predicateForData = criteriaBuilder.or(
criteriaBuilder.like(root.get("firstName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("lastName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectId").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectName"), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectBudget").as(String.class), "%" + employeeRequestDTO.getFilterText() + "%"),
criteriaBuilder.like(root.get("projectLocation"), "%" + employeeRequestDTO.getFilterText() + "%"));
/** Combine both predicates */
return criteriaBuilder.and(predicateForEmployee, predicateForData);
@Override
public Page<EmployeeProjectView> findEmployeeProjectsBySpecification(EmployeeRequestDTO employeeRequestDTO)
{
return employeeProjectViewRepository.findAll(getSpecification(employeeRequestDTO), PageRequest.of(employeeRequestDTO.getCurrentPageNumber(), employeeRequestDTO.getPageSize(),
Sort.by(isNotNullOrEmpty(employeeRequestDTO.getSortDirection()) ? Sort.Direction.fromString(employeeRequestDTO.getSortDirection()) : Sort.Direction.DESC, employeeRequestDTO.getSortColumnName())));
}
マルチカラム検索を実装する最後の方法は
@Query
注釈.public interface EmployeeProjectViewRepository extends JpaRepository<EmployeeProjectView, Long>, JpaSpecificationExecutor<EmployeeProjectView>
{
@Query(value = "SELECT e FROM EmployeeProjectView as e WHERE e.employeeId=:employeeId and (:inputString is null or e.lastName like %:inputString% ) and " +
"(:inputString is null or e.firstName like %:inputString%) and (:inputString is null or concat(e.projectId,'') like %:inputString%) and " +
" (:inputString is null or e.projectName like %:inputString%) and (:inputString is null or concat(e.projectBudget,'') like %:inputString%) and "+
" (:inputString is null or e.projectLocation like %:inputString%)"
)
Page<EmployeeProjectView> findAllByInputString(Long employeeId, String inputString, Pageable pageable);
}
上記のように、クエリの注釈を使用してemployeeId
従業員IDと検索テキスト(InputString)パラメータをパラメータとして、列の残りを一致させます.時inputString
がNULLでない場合、すべてのカラムに対して比較され、結果が結合されます.プロジェクトを実行する
$ docker-compose -f src/main/resources/docker-compose.yml up
$ cd src/webapp
$ npm install
$ ng serve --watch
従業員プロジェクト
The user specified as a definer (‘’@’’) does not exist
MySQLデータベースへの接続drop view if exists employee_project_view;
create view employee_project_view as
select distinct employee_id,
first_name,
last_name,
project_id,
name as project_name,
location as project_location,
budget as project_budget
from employee,
employee_project,
project
where employee.id = employee_project.employee_id
and employee_project.project_id = project.id;
今、我々はすべてを使用して、どのアプローチを見てきた?これが私の推薦ですReference
この問題について(バネデータJPAを用いた複数カラム間のデータ検索), 我々は、より多くの情報をここで見つけました https://dev.to/pavankjadda/search-data-across-multiple-columns-using-spring-data-jpa-8edテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol