我沒有執行代碼,但給了正確的導入語句,至少編譯。根據您的實體定義,某些屬性可能需要進行調整,無論如何,您應該瞭解如何處理此問題。
我的條件查詢是基於以下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));
}
}
可以很明顯的替代Map<String, String>
與Iterable<TerminalProperty>
,但因爲他們似乎被綁定到特定的Terminal
會感到奇怪。
我希望避免規範和編程建立查詢,但顯然這是不可能的。非常感謝您的詳細解答。 – Ismail 2013-04-24 07:03:37
不客氣。如果您希望避免使用'Specification',但您想使用Spring Data JPA,則您可以直接使用JPA標準API? – skirsch 2013-04-24 07:27:14