【问题标题】:How to write JPA IN query to check a collection has given set of values.?如何编写 JPA IN 查询来检查集合是否给定了一组值。?
【发布时间】:2021-05-14 21:08:00
【问题描述】:
@javax.persistence.Entity
public class Device extends AbstractEntity implements Serializable {
    @ElementCollection
    @LazyCollection(LazyCollectionOption.FALSE)
    private List<String> labels;
}

现在我需要检查给定标签集是否存在哪些设备。

以下是我尝试过的查询器。

@Query("SELECT DISTINCT d FROM Device d JOIN d.labels l WHERE d.entity.id IN :entity_ids AND l IN :labels ")
List<Device> find(@Param("entity_ids") Set<Long> entityIds, @Param("labels") Set<String> labels);

@Query("SELECT d FROM Device d WHERE d.entity.id IN :entity_ids AND  d.labels IN :labels") List<Device> 
find(@Param("entity_ids") Set<Long> entityIds, @Param("labels") Set<String> labels);

这以 en 错误结束。

org.springframework.dao.InvalidDataAccessApiUsageException: 参数 值 [D2_label1] 与预期类型 [java.util.Collection] 不匹配 (n/a)];嵌套异常是 java.lang.IllegalArgumentException: 参数值 [D2_label1] 与预期类型不匹配 [java.util.Collection (n/a)] 在 org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:373) 在 org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:255)

谁能给我建议一个解决方案?

【问题讨论】:

    标签: spring-boot hibernate spring-data-jpa


    【解决方案1】:

    你不能做你想做的事。正如documentation 中所述:

    IN 谓词检查特定值是否在值列表中。它的语法是:

    in_expression ::= single_valued_expression [NOT] IN single_valued_list

    single_valued_list ::= constructor_expression | (子查询)| collection_valued_input_parameter

    constructor_expression ::= (表达式[, 表达式]*)

    single_valued_expression 的类型和single_valued_list 中的各个值必须一致。

    JPQL 将此处的有效类型限制为字符串、数字、日期、时间、时间戳和枚举类型,而在 JPQL 中,single_valued_expression 只能指:

    • “状态字段”,这是它对简单属性的称呼。具体来说,这不包括关联和组件/嵌入属性。

    • 实体类型表达式。请参阅实体类型。

    在 HQL 中,single_valued_expression 可以指代更广泛的表达式类型集。 允许单值关联,组件/嵌入式属性也是如此,尽管该功能取决于底层数据库中对元组或“行值构造函数语法”的支持级别。

    所以,我看到了以下方法:

    1. 按以下方式重写您的查询:
    @Query("SELECT DISTINCT d FROM Device d join fetch d.labels WHERE d.entity.id IN :entity_ids")
    List<Device> find(@Param("entity_ids") Set<Long> entityIds);
    

    然后在java代码中做进一步的过滤。

    1. 例如以这种方式重写您的实体映射:
    @Entity
    public class Device extends AbstractEntity implements Serializable {
    
        @OneToMany
        private List<Label> labels;
    }
    
    @Entity
    public class Label
    {
       @Id
       private Long id;
    
       private String text;
    }
    

    然后使用以下查询:

    @Query("SELECT DISTINCT d FROM Device d join fetch d.labels l WHERE d.entity.id IN :entity_ids and l.text in :labels")
    List<Device> find(@Param("entity_ids") Set<Long> entityIds, @Param("labels") Set<String> labels);
    

    附:另请注意,LazyCollectionOption.FALSE 已被弃用,因为您应该使用 @ElementCollection 的 JPA FetchType 属性。见this。

    【讨论】:

      【解决方案2】:

      在我看来,您应该在括号中写上IN 子句:

      @Query("SELECT DISTINCT d FROM Device d JOIN d.labels l WHERE d.entity.id IN (:entity_ids) AND l IN (:labels)")
      List<Device> find(@Param("entity_ids") Set<Long> entityIds, @Param("labels") Set<String> labels);
      
      @Query("SELECT d FROM Device d WHERE d.entity.id IN (:entity_ids) AND  d.labels IN (:labels)") List<Device> 
      find(@Param("entity_ids") Set<Long> entityIds, @Param("labels") Set<String> labels);
      

      【讨论】:

      • 嗨@Patrick 感谢您的回答。但它也不起作用。以以下错误结束。 org.springframework.dao.InvalidDataAccessResourceUsageException:无法提取结果集; SQL [不适用];嵌套异常是 org.hibernate.exception.SQLGrammarException: could not extract ResultSet at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:279) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible (HibernateJpaDialect.java:253)
      【解决方案3】:

      这是正确的:

      @Query("SELECT DISTINCT d FROM Device d JOIN d.labels l WHERE d.entity.id IN :entity_ids AND l IN :labels ")
      List<Device> find(@Param("entity_ids") Set<Long> entityIds, @Param("labels") Set<String> labels);
      

      您能否分享您在使用此查询时遇到的错误?

      【讨论】:

      • 您的 SQL 语法有误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 '))' 附近使用正确的语法 2021-02-12 16:55:38,379 INFO [http-nio-8082-exec-3] UUID:6f6f7400- 9716-43e4-8ffb-d4740825fc18 lk.adl.iot.sima.controller.GlobalExceptionController:发生意外异常:org.springframework.dao.InvalidDataAccessResourceUsageException:无法提取 ResultSet; SQL [不适用];嵌套异常是 org.hibernate.exception.SQLGrammarException: could not extract ResultSet
      • 那么,MySQL报错的SQL和错误是什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      • 2015-08-14
      • 2016-03-28
      • 2011-11-22
      • 2011-03-22
      • 2019-09-11
      相关资源
      最近更新 更多