如何使用谓词在spring数据jpa @Query中检查集合是否为空

编程入门 行业动态 更新时间:2024-10-26 14:35:08
本文介绍了如何使用谓词在spring数据jpa @Query中检查集合是否为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我的spring数据jpa存储库中有以下查询:

@Query(" SELECT table1 FROM Table1 table1"+" INNER JOIN FETCH table1.error错误"+" WHERE table1.date =?1"+" AND(COALESCE(?2)为NULL或(table1.code IN?2)).+" AND(COALESCE(?3)为NULL或(error.errorCode IN?3)).)列表<表1>findByFilter(日期,List< String>代码,List< String> errorCodes);

当我运行此查询时,它通过控制台向我显示此错误:

org.postgresql.util.PSQLException:错误:不存在运算符:字符变化= bytea提示:没有运算符匹配给定的名称和参数类型.您可能需要添加显式类型转换.位置:1642

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

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

解决方案

具有一个参数的
  • COALESCE 没有任何意义.这是一个缩写的CASE表达式,它返回第一个非空操作数.(请参见此)

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

  • 与IN谓词有关的文档:

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

  • 我建议您也避免使用过时的 Date ,而改用java 8 Date/Time API.
  • 因此,考虑到上述所有因素,您应该使用动态查询,因为@SimonMartinelli的注释中也建议使用动态查询.特别是,您可以查看规范.

    假设您具有以下映射:

    @Entity公共类错误{@ID私人Long ID;私有字符串errorCode;//...}@实体公共课表1{@ID私人Long ID;私有LocalDateTime日期;私有字符串代码;@多多私人错误错误;//...}

    您可以编写以下规范:

    import javax.persistence.criteria.JoinType;导入javax.persistence.criteria.Predicate;导入org.springframework.data.jpa.domain.Specification;导入org.springframework.util.CollectionUtils;公共类TableSpecs{公共静态规范<表1>findByFilter(LocalDateTime日期,List< String>代码,List< String> errorCodes){返回(根,查询,构建器)->{root.fetch(错误",JoinType.LEFT);谓词结果= builder.equal(root.get("date"),date);如果(!CollectionUtils.isEmpty(codes)){结果= builder.and(结果,root.get(代码").in(代码)));}如果(!CollectionUtils.isEmpty(errorCodes)){结果= builder.and(结果,root.get(错误").get(错误代码").in(错误代码));}返回结果;};}}公共接口TableRepository扩展了CrudRepository< Table1,Long>,JpaSpecificationExecutor< Table1>.{默认List< Table1>findByFilter(LocalDateTime日期,List< String>代码,List< String> errorCodes){返回findAll(TableSpecs.findByFilter(date,codes,errorCodes));}}

    然后使用它:

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

    I have this query in my spring data jpa repository:

    @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);

    When I run this query, it shows me this error by console:

    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

    However if I run the query without the (COALESCE (?2) IS NULL OR part, just the table1.code IN ?2, it does work

    Does anyone know what this error could be due to?

    解决方案

  • COALESCE with one parameter does not make sense. This is an abbreviated CASE expression that returns the first non-null operand. (See this)

  • I would suggest you to use named parameters instead of position-based parameters. As it's stated in the documentation this makes query methods a little error-prone when refactoring regarding the parameter position.

  • As it's stated in documentation related to the IN predicate:

  • The list of values can come from a number of different sources. In the constructor_expression and collection_valued_input_parameter, the list of values must not be empty; it must contain at least one value.

  • I would suggest you also avoid to use outdated Date and use instead java 8 Date/Time API.
  • So, taken into account all above, you should use a dynamic query as it was suggested also in comments by @SimonMartinelli. Particularly you can have a look at the specifications.

    Assuming that you have the following mapping:

    @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; // ... }

    you can write the following specification:

    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)); } }

    and then use it:

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

    更多推荐

    如何使用谓词在spring数据jpa @Query中检查集合是否为空

    本文发布于:2023-10-25 14:28:15,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1527220.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:谓词   如何使用   为空   数据   Query

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!