使用枚举列表作为参数的Spring Data查询方法中使用IN关键字

3
我将使用Spring Data JPA (4.3.5)存储库,并使用IN关键字子句的查询方法,其中一个List<Enum>字段作为参数。问题是它没有按照我期望的方式工作
给定这样的实体:
@Entity
@Table(name = "R_REPRESENTACIO")
public class Representacio {

    @Enumerated(EnumType.STRING)
    private Estat estat;   

    ...
    //getters and setters
    ...
}

使用以下SQL语句:

CREATE TABLE R_REPRESENTACIO (
  UUID NUMBER(19) NOT NULL,
  ...
  ESTAT VARCHAR2(255) NULL,
  ...
);

Estat 是一个枚举类,例如:

public enum Estat {
        VALIDA,
        PENDENT_VALIDACIO,
        PENDENT_DOCUMENTACIO,
        ...
}

一个像这样的JPA存储库:

public interface RepresentacioRepository extends JpaRepository<Representacio, Long> {
    List<Representacio> findAllByEstatIn(List<Estat> estats);
}

当我运行(集成测试类)时:
List<Estat> estats = 
  Arrays.asList(Estat.VALIDA,Estat.PENDENT_DOCUMENTACIO,Estat.PENDENT_VALIDACIO);
List<cat.aoc.representa.domain.entity.representacio.Representacio> allByEstatIn = representacioRepository.findAllByEstatIn(estats);

生成的SQL(在内存中的H2数据库中)如下所示:
2018-08-01 12:30:48.534--ServerSession(1175154004)--Connection(384887832)--Thread(Thread[main,5,main])--SELECT UUID, .... FROM R_REPRESENTACIO WHERE (ESTAT IN ((?,?,?)))
    bind => [VALIDA, PENDENT_DOCUMENTACIO, PENDENT_VALIDACIO]

没有抛出任何No SQL异常并且没有返回任何结果。 但是这个应该返回一个结果,因为等效的SQL语句会返回一个结果:
SELECT count(*) FROM R_REPRESENTACIO WHERE ESTAT IN ('VALIDA','PENDENT_DOCUMENTACIO','PENDENT_VALIDACIO');

COUNT(*)
----------
         1

我所看到的独特区别在于我是如何将IN子句的参数用''括起来的(该列是VARCHAR类型)。

我不知道从JPA存储库生成的SQL为什么没有返回结果。 (我也尝试过使用 findAllByEstatIsIn(List<Estat> estats),但也没有得到任何结果)。

有什么建议/解释吗?

PS:通过权宜之计解决了问题(不太满意)

List<Representacio> findAllByEstatOrEstatOrEstat(Estat estat, Estat estat2, Estat estat3);

但是这种做法在很多方面都不美观且错误...

由于您使用了@Enumerated(EnumType.STRING),所以列是varchars,但是您的参数是枚举列表。您尝试过使用字符串列表吗? - mrkernelpanic
是的,我尝试了一种仓库方法,类似于findAllByEstatIn(List <String> estats),然后运行repo.findAllByEstatIn(Arrays.asList(“VALIDA”,“PENDENT_VALIDACIO”…))但是抛出java.lang.ClassCastException:java.lang.String无法转换为java.lang.Enum。 - exoddus
1
你尝试过自己编写查询吗?@Query("select r FROM Representacio r where r.estat in :estats") - mrkernelpanic
如果您跳过“全部”并使用 List<Representacio> findByEstatIn(List<Estat> estats) 会怎样? - StanislavL
@mrkernelpanic,我希望了解IN子句的工作原理,以及如何尽可能避免编写大量的SQL语句,但在这种情况下,您的解决方案简单且符合我的预期。您的解决方案很好用! - exoddus
显示剩余2条评论
2个回答

1
我建议添加一个类型为List<String>的参数,并添加转换器String -> Enum,这样Spring就能够进行转换。所以,基本上是这样的:List<Representacio> findByEstatIn(List<String> estats);
@Configuration
public class ConverterConfiguration extends RepositoryRestConfigurerAdapter {
  @Autowired
  private EstatsConverter estatsConverter;

  @Override
  public void configureConversionService(ConfigurableConversionService conversionService) {
    conversionService.addConverter(estatsConverter);

    super.configureConversionService(conversionService);
  }
    3.
@Component
public class EstatsConverter implements Converter<String, Estat> {

    @Override
    public Estat convert(String source) {
        return Estat.fromString(source);
    }
}

我不确定那是否有效,但我记得之前在MongoDB中有类似的操作。如果你尝试了可以告诉我。


我喜欢你的方法,但我没有使用REST存储库,而是用JpaRepository,无法使用RepositoryRestConfigurerAdapter类。我一直在寻找类似于JpaRepository的解决方案,但我找不到... - exoddus

1
使用Spring Data JPA和JPQL非常简单:
@Repository
public interface RepresentacioRepository extends JpaRepository<Representacio, Long> {

    @Query("select r from Representacio r where r.estat in :estat2")
    List<Representacio> findByEnumEstat(@Param("estat2") List<Estat> estatList);
}


我对了解在查询方法中如何使用枚举列表的IN子句感兴趣,但正如@mrkernelpanic在问题中评论的那样,这个解决方案解决了我的用例。 - exoddus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接