임의 AND 절이 있는 동적 스프링 데이터 jpa 저장소 쿼리
사용하고 있습니다.Spring data jpa repositories
, 다른 필드로 검색 기능을 제공해야 합니다.검색 전에 필드를 입력하는 것은 선택사항입니다.저는 5개의 분야가 있습니다.EmployeeNumber
,Name
,Married
,Profession
그리고.DateOfBirth
.
여기서 나는 사용자별로 주어진 값으로만 질의해야 하며 다른 필드는 무시해야 합니다.
Input : EmployeeNumber: ,Name:St,Married: ,Professsion:IT,DateOfBirth:
Query : Select * from Employee e where Name like 'St%' and Profession like 'IT%';
Input : EmployeeNumber:10,Name: ,Married: ,Professsion:IT,DateOfBirth:
Query : Select * from Employee e where EmployeeNumber like '10%' and Profession like 'IT%';
그래서 여기서는 입력한 값과 쿼리를 고려하고 있습니다.이 경우 Spring data는 본 게시물에 언급된 것과 같이 제한이 있습니다. (확장이 불가능하고 가능한 모든 쿼리를 작성해야 함) 제가 사용하고 있는Querydsl
, 하지만 문제는 여전히 존재합니다.null
필드는 무시하고 가능한 거의 모든 쿼리를 개발해야 합니다.이 점에서.case 31 queries
. 검색 필드가6,7,8...
??
선택 필드로 검색 옵션을 구현하는 가장 좋은 방법은 무엇입니까?
Spring-data에서 제공하는 Specifications를 즉시 사용할 수 있으며 기준 API를 사용하여 쿼리를 프로그래밍 방식으로 구축할 수 있습니다.규격을 지원하기 위해 Jpa 규격을 사용하여 저장소 인터페이스를 확장할 수 있습니다.실행기 인터페이스
public interface CustomerRepository extends SimpleJpaRepository<T, ID>, JpaSpecificationExecutor {
}
부가 인터페이스 (Jpa 규격)실행자)는 다양한 방법으로 사양을 실행할 수 있는 메서드를 제공합니다.
예를 들어 findAll 메서드는 규격과 일치하는 모든 엔터티를 반환합니다.
List<T> findAll(Specification<T> spec);
사양 인터페이스는 다음과 같습니다.
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder);
}
좋아요, 그럼 전형적인 사용 사례는 무엇인가요?규격을 쉽게 사용하여 엔티티 위에 확장 가능한 술어 집합을 구축할 수 있으며, 이를 통해 필요한 모든 조합에 대한 쿼리(메소드)를 선언할 필요 없이 JpaRepository와 결합하여 사용할 수 있습니다.여기 예가 있습니다: 예 2.15.고객사양
public class CustomerSpecs {
public static Specification<Customer> isLongTermCustomer() {
return new Specification<Customer>() {
public Predicate toPredicate(
Root<Customer> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
LocalDate date = new LocalDate().minusYears(2);
return builder.lessThan(root.get('dateField'), date);
}
};
}
public static Specification<Customer> hasSalesOfMoreThan(MontaryAmount value) {
return new Specification<Customer>() {
public Predicate toPredicate(
Root<T> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
// build query here
}
};
}
}
비즈니스 요구사항 추상화 수준에 대한 몇 가지 기준을 표현하고 실행 가능한 사양을 만들었습니다.따라서 클라이언트는 다음과 같이 규격을 사용할 수 있습니다.
List customers = customerRepository.findAll(isLongTermCustomer());
사양 예제 2.17을 결합할 수도 있습니다.조합사양
MonetaryAmount amount = new MonetaryAmount(200.0, Currencies.DOLLAR);
List<Customer> customers = customerRepository.findAll(
where(isLongTermCustomer()).or(hasSalesOfMoreThan(amount)));
보다시피 사양은 사양을 체인으로 연결하고 결합하는 몇 가지 글루 코드 방식을 제공합니다.따라서 데이터 액세스 계층을 확장하는 것은 새로운 Specification 구현을 생성하고 이미 존재하는 구현과 결합하는 문제일 뿐입니다.
복잡한 사양을 생성할 수 있습니다. 여기 예가 있습니다.
public class WorkInProgressSpecification {
public static Specification<WorkInProgress> findByCriteria(final SearchCriteria searchCriteria) {
return new Specification<WorkInProgress>() {
@Override
public Predicate toPredicate(
Root<WorkInProgress> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<Predicate>();
if (searchCriteria.getView() != null && !searchCriteria.getView().isEmpty()) {
predicates.add(cb.equal(root.get("viewType"), searchCriteria.getView()));
}
if (searchCriteria.getFeature() != null && !searchCriteria.getFeature().isEmpty()) {
predicates.add(cb.equal(root.get("title"), searchCriteria.getFeature()));
}
if (searchCriteria.getEpic() != null && !searchCriteria.getEpic().isEmpty()) {
predicates.add(cb.equal(root.get("epic"), searchCriteria.getEpic()));
}
if (searchCriteria.getPerformingGroup() != null && !searchCriteria.getPerformingGroup().isEmpty()) {
predicates.add(cb.equal(root.get("performingGroup"), searchCriteria.getPerformingGroup()));
}
if (searchCriteria.getPlannedStartDate() != null) {
System.out.println("searchCriteria.getPlannedStartDate():" + searchCriteria.getPlannedStartDate());
predicates.add(cb.greaterThanOrEqualTo(root.<Date>get("plndStartDate"), searchCriteria.getPlannedStartDate()));
}
if (searchCriteria.getPlannedCompletionDate() != null) {
predicates.add(cb.lessThanOrEqualTo(root.<Date>get("plndComplDate"), searchCriteria.getPlannedCompletionDate()));
}
if (searchCriteria.getTeam() != null && !searchCriteria.getTeam().isEmpty()) {
predicates.add(cb.equal(root.get("agileTeam"), searchCriteria.getTeam()));
}
return cb.and(predicates.toArray(new Predicate[] {}));
}
};
}
}
여기 JPA Respositorys 문서가 있습니다.
QueryDSL(4.x) 및 querydsl-jpa의 새 주 버전을 사용하려면 변경해야 합니다.
우리의 프로젝트 중 하나에서, 우리는QueryDSL
와 함께QueryDslPredicateExecutor<T>
.
public Predicate createPredicate(DataEntity dataEntity) {
QDataEntity qDataEntity = QDataEntity.dataEntity;
BooleanBuilder booleanBuilder = new BooleanBuilder();
if (!StringUtils.isEmpty(dataEntity.getCnsiConsumerNo())) {
booleanBuilder
.or(qDataEntity.cnsiConsumerNo.contains(dataEntity.getCnsiConsumerNo()));
}
if (!StringUtils.isEmpty(dataEntity.getCnsiMeterNo())) {
booleanBuilder.or(qDataEntity.cnsiMeterNo.contains(dataEntity.getCnsiMeterNo()));
}
return booleanBuilder.getValue();
}
저장소에서 이를 사용할 수 있습니다.
@Repository
public interface DataEntityRepository
extends DaoRepository<DataEntity, Long> {
어디에DaoRepository
@NoRepositoryBean
public interface DaoRepository<T, K extends Serializable>
extends JpaRepository<T, K>,
QueryDslPredicateExecutor<T> {
}
그러면 리포지토리 술어 메서드를 사용할 수 있기 때문입니다.
Iterable<DataEntity> results = dataEntityRepository.findAll(dataEntityPredicateCreator.createPredicate(dataEntity));
갖기 위해QClasses
, pom.xml에 QueryDSL APT Maven 플러그인을 지정해야 합니다.
<build>
<plugins>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>maven-apt-plugin</artifactId>
<version>1.0.4</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
종속성은
<!-- querydsl -->
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
또는 그라들의 경우:
sourceSets {
generated
}
sourceSets.generated.java.srcDirs = ['src/main/generated']
configurations {
querydslapt
}
dependencies {
// other deps ....
compile "com.mysema.querydsl:querydsl-jpa:3.6.3"
compile "com.mysema.querydsl:querydsl-apt:3.6.3:jpa"
}
task generateQueryDSL(type: JavaCompile, group: 'build', description: 'Generates the QueryDSL query types') {
source = sourceSets.main.java
classpath = configurations.compile + configurations.querydslapt
options.compilerArgs = [
"-proc:only",
"-processor", "com.mysema.query.apt.jpa.JPAAnnotationProcessor"
]
destinationDir = sourceSets.generated.java.srcDirs.iterator().next()
}
compileJava {
dependsOn generateQueryDSL
source generateQueryDSL.destinationDir
}
compileGeneratedJava {
dependsOn generateQueryDSL
classpath += sourceSets.main.runtimeClasspath
}
Spring Data JPA 1.10부터는 예제별 쿼리라는 다른 옵션이 있습니다.저장소는 다음과 별도로 구현해야 합니다.JpaRepository
또한 쿼리 기준예시다음과 같은 메서드를 얻을 수 있는 실행자 인터페이스:
<S extends T> Iterable<S> findAll(Example<S> example)
그런 다음 다음 검색할 예제를 만듭니다.
Employee e = new Employee();
e.setEmployeeNumber(getEmployeeNumberSomewherFrom());
e.setName(getNameSomewhereFrom());
e.setMarried(getMarriedSomewhereFrom());
e.setProfession(getProfessionSomewhereFrom());
e.setDateOfBirth(getDateOfBirthSomewhereFrom());
그 다음:
employeeRepository.findAll(Example.of(e));
일부 매개 변수가 null일 경우 WHERE 절에 포함되지 않으므로 동적 쿼리를 얻을 수 있습니다.
문자열 특성의 일치를 세분화하려면 의 를 참조하십시오.
ExampleMatcher
사건에 민감하지 않은 사람이like
는 예를 들어 다음과 같습니다.
ExampleMatcher matcher = ExampleMatcher.matching().
withMatcher("profession", ExampleMatcher.GenericPropertyMatcher.of(ExampleMatcher.StringMatcher.CONTAINING).ignoreCase());
QBE 예제: https://github.com/spring-projects/spring-data-examples/tree/master/jpa/query-by-example
게임에 좀 늦었지만 답이 너무 복잡해서...만약 당신이 당신의 개체의 필드를 바꾸면 어떻게 됩니까?다른 엔티티에 대한 검색을 지원하려면 어떻게 해야 합니까?
그냥 이 라이브러리를 사용해도 됩니다: https://github.com/turkraft/spring-filter
다음과 같은 검색 쿼리를 실행할 수 있습니다.
/search?filter=평균(ratings)> 4.5 및 brand.name in ('audi', '랜드로버') 및 (2018년 또는 km < 50000)에서 색상: '흰색' 및 사고가 비어 있습니다.
Spring's Pageable과 함께 다음 페이지를 호출할 수 있습니다.&page=11&size=20
언급URL : https://stackoverflow.com/questions/28874135/dynamic-spring-data-jpa-repository-query-with-arbitrary-and-clauses
'programing' 카테고리의 다른 글
두 개의 데이터 프레임을 결합하려면 어떻게 해야 합니까? (0) | 2023.10.29 |
---|---|
웨이포인트를 저장하고 비교를 수행하는 가장 효율적인 방법은 무엇입니까? (0) | 2023.10.29 |
fill_parent와 wrap_content의 차이점은 무엇입니까? (0) | 2023.10.29 |
WooCommerce 체크아웃 필드 사이에 제목을 추가하는 방법 (0) | 2023.10.29 |
jQuery를 사용하여 비디오 src를 어떻게 변경합니까? (0) | 2023.10.29 |