【问题标题】:Spring Data Jpa, select based on two column valuesSpring Data Jpa,基于两列值选择
【发布时间】:2020-01-23 14:48:25
【问题描述】:
早安,
我有下表:
_____________________
Name Status Num
A Good 6
B Bad 6
C Bad 7
我想选择 "Status = 'Good' AND Num = '6'" OR "Status = 'Bad' AND Num = '7'" 的所有行
所以我会从上述参考数据中选择名称为 A 和 C 的行。
我希望能够传入两个大小相等的列表(按照我希望构建查询的方式排序),但一直无法解决这个问题。标准查询 (SelectXByStatusAndNum) 查询使用“IN”语句生成 SQL,并返回上述数据中的所有 3 行,而不是仅返回两行。
任何见解表示赞赏
【问题讨论】:
标签:
sql
jpa
spring-data-jpa
spring-data
【解决方案1】:
我认为最好的方法是在存储库中使用@Query 注释:
@Entity
@Table(name = "table_name")
public class TableName {
@Id
@Basic(optional = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "status")
private String status;
@Column(name = "num")
private Integer num;
/**
* getters/setters, etc
**/
public interface TableNameRepository extends CrudRepository<TableName, Long> {
@Query("select t from TableName t where (status = :status1 and num = :num1 or status = :status2 and num = :num2)")
List<TableName> findByStatusAndNumOrStatusAndNum(@Param("status1") String status1,
@Param("num1") Integer num1, @Param("status2") String status2, @Param("num2") Integer num2);
}
这是一种获取给定参数值的方法。在将集合作为参数的情况下,由于 RDBMS 概念,没有收件箱。您可以根据键值参数编写一些java代码并收集结果:
public interface TableNameRepository extends CrudRepository<TableName, Long> {
List<TableName> findByStatusAndNumIn(String status, Collection<Integer> nums);
}
List<TableName> result = new ArrayList<>();
List<TableName> itemGood = findByStatusAndNumIn("Good", numsGood);
List<TableName> itemBad = findByStatusAndNumIn("Bad", numsBad);
result.addAll(itemGood);
result.addAll(itemBad);
【解决方案2】:
我建议创建一个同时具有 status 和 num 的对象,并提供一个列表,而不是相等大小的列表 - 我在下面将其称为 CustomCriteria。由于没有直接的方法可以使用标准的 spring 数据查询方法来处理这个问题,我认为最好的方法是使用自定义存储库中的条件构建器来执行此操作,该存储库根据条件条目从 AND 谓词列表中构建 OR 列表提供的清单。例如:
public List<YourTable> findMatching(List<CustomCriteria> customCriteriaList) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<YourTable> criteriaQuery = criteriaBuilder.createQuery(YourTable.class);
Root<YourTable> itemRoot = criteriaQuery.from(YourTable.class);
List<Predicate> predicates = new ArrayList<>(customCriteriaList.size());
for (CustomCriteria customCriteria : customCriteriaList) {
Predicate predicateForNum
= criteriaBuilder.equal(itemRoot.get("num"), customCriteria.getNum());
Predicate predicateForStatus
= criteriaBuilder.equal(itemRoot.get("status"), customCriteria.getStatus());
predicates.add(criteriaBuilder.and(predicateForNum, predicateForStatus));
}
Predicate finalPredicate = criteriaBuilder.or(predicates.toArray(new Predicate[predicates.size()]));
criteriaQuery.where(finalPredicate);
return entityManager.createQuery(criteriaQuery).getResultList();
}