[英]spring-data query method with a list as arguments
我们必须从数据库中查询数据,我们需要在数据库中查找与键值对列表匹配的实体。 我们认为使用Spring Data JPA是一个好主意,因为我们也需要分页。
我们创建的表如下所示:
terminal(ID,NUMBER,NAME);
terminal_properties(ID,KEY,VALUE,TERMINAL_FK);
是否可以定义查询方法以获取具有包含给定键/值对的属性的所有终端?
这样的事情: List <Terminal> findByPropertiesKeyAndValue(List <Property>);
我没有执行代码,但是给出正确的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 {
}
扩展JpaSpecificationExecutor
以便使用标准API很重要。
然后,您可以构建这样的条件查询:
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
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.