如何在谓词中检查spring数据jpa@Query中的集合是否为null



我的spring数据jpa存储库中有这个查询:

@Query("SELECT table1 FROM Table1 table1 "
+ "INNER JOIN FETCH table1.error error"
+ "WHERE table1.date = ?1 "
+ "AND (COALESCE(?2) IS NULL OR (table1.code IN ?2)) "
+ "AND (COALESCE(?3) IS NULL OR (error.errorCode IN ?3)) ")
List<Table1> findByFilter(Date date, List<String> codes, List<String> errorCodes);

当我运行这个查询时,它通过控制台显示了这个错误:

org.postgresql.util.PSQLException: ERROR: operator does not exist: character varying = bytea
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
Position: 1642

但是,如果我运行的查询没有(COALESCE (?2) IS NULL OR部分,只有table1.code IN ?2部分,它确实可以

有人知道这个错误可能是由于什么原因造成的吗?

  1. COALESCE只有一个参数是没有意义的。这是一个缩写CASE表达式,返回第一个非null操作数。(见此(

  2. 我建议您使用命名参数,而不是基于位置的参数。正如文档中所述,这使得查询方法在重构参数位置时有点容易出错。

  3. 正如在与in谓词相关的文档中所述:

值列表可以来自许多不同的来源。在constructor_expressioncollection_valued_input_parameter中,值列表不得为空;它必须至少包含一个值

  1. 我建议您也不要使用过时的Date,而是使用java 8日期/时间API

因此,考虑到以上所有因素,您应该使用动态查询,正如@SimonMartinelli在评论中所建议的那样。特别是你可以看看规格。

假设您有以下映射:

@Entity
public class Error
{
@Id
private Long id;
private String errorCode;
// ...
}
@Entity
public class Table1
{
@Id
private Long id;
private LocalDateTime date;
private String code;
@ManyToOne
private Error error;
// ...
}

您可以编写以下规范:

import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.CollectionUtils;
public class TableSpecs
{
public static Specification<Table1> findByFilter(LocalDateTime date, List<String> codes, List<String> errorCodes)
{
return (root, query, builder) -> {
root.fetch("error", JoinType.LEFT);
Predicate result = builder.equal(root.get("date"), date);

if (!CollectionUtils.isEmpty(codes)) {
result = builder.and(result, root.get("code").in(codes));
}
if (!CollectionUtils.isEmpty(errorCodes)) {
result = builder.and(result, root.get("error").get("errorCode").in(errorCodes));
}
return result;
};
}
}
public interface TableRepository extends CrudRepository<Table1, Long>, JpaSpecificationExecutor<Table1>
{
default List<Table1> findByFilter(LocalDateTime date, List<String> codes, List<String> errorCodes)
{
return findAll(TableSpecs.findByFilter(date, codes, errorCodes));
}
}

然后使用它:

List<Table1> results = tableRepository.findByFilter(date, Arrays.asList("TBL1"), Arrays.asList("ERCODE2")));

最新更新