나는 코드를 실행하지 않았지만, 정확한 import 문이 주어지면 적어도 이것을 컴파일한다. 엔티티 정의에 따라 일부 속성을 적용해야 할 수도 있으며 어떤 경우에도이 속성에 접근하는 방법에 대한 아이디어를 얻으십시오.
내 기준 쿼리는 다음과 같은 SQL을 기반으로합니다
SELECT * FROM TERMINAL
WHERE ID IN (
SELECT TERMINAL_FK FROM TERMINAL_PROPERTIES
WHERE (KEY = 'key1' AND VALUE = 'value1')
OR (KEY = 'key2' AND VALUE = 'value2')
...
GROUP BY TERMINAL_FK
HAVING COUNT(*) = 42
)
각 이름/값 쌍을 나열
및 42
은 단순히 이름/값 쌍의 수를 나타냅니다.
그래서 나는이 같은 저장소를 정의 가정 :
public interface TerminalRepository extends CrudRepository<Terminal, Long>, JpaSpecificationExecutor {
}
그것은 기준 API의 사용을 만들기 위해 JpaSpecificationExecutor
을 확장하는 것이 중요합니다.
그런 다음 당신은이 같은 기준에 쿼리를 구축 할 수 있습니다 :
public class TerminalService {
private static Specification<Terminal> hasProperties(final Map<String, String> properties) {
return new Specification<Terminal>() {
@Override
public Predicate toPredicate(Root<Terminal> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
// SELECT TERMINAL_FK FROM TERMINAL_PROPERTIES
Subquery<TerminalProperty> subQuery = query.subquery(TerminalProperty.class);
Root propertyRoot = subQuery.from(TerminalProperty.class);
subQuery.select(propertyRoot.get("terminal.id"));
Predicate whereClause = null;
for (Map.Entry<String, String> entry : properties.entrySet()) {
// (KEY = 'key1' AND VALUE = 'value1')
Predicate predicate = builder.and(builder.equal(propertyRoot.get("key"),
entry.getKey()), builder.equal(propertyRoot.get("value"), entry.getValue()));
if (whereClause == null) {
whereClause = predicate;
} else {
// (...) OR (...)
whereClause = builder.or(whereClause, predicate);
}
}
subQuery.where(whereClause);
// GROUP BY TERMINAL_FK
subQuery.groupBy(propertyRoot.get("terminal.id"));
// HAVING COUNT(*) = 42
subQuery.having(builder.equal(builder.count(propertyRoot), properties.size()));
// WHERE ID IN (...)
return query.where(builder.in(root.get("id")).value(subQuery)).getRestriction();
}
};
}
@Autowired
private TerminalRepository terminalRepository;
public Iterable<Terminal> findTerminalsWith(Map<String, String> properties) {
// this works only because our repository implements JpaSpecificationExecutor
return terminalRepository.findAll(hasProperties(properties));
}
}
당신은 분명히 Iterable<TerminalProperty>
와 Map<String, String>
을 대체 할 수 있습니다, 그들은 특정 Terminal
에 바인딩하는 것 때문에 그 이상한 느낌을 받겠지만.
사양을 피하고 프로그래밍 방식으로 쿼리를 작성하기를 바랬지 만 분명히 불가능합니다. 자세한 답변을 주셔서 감사합니다. – Ismail
반갑습니다. 그리고 'Specification'을 사용하지 않으려면 JPA criteria API를 직접 사용할 수 있지만 Spring Data JPA를 사용하고 싶습니까? – skirsch