Spring Data JPA:当Collection类型的repository方法参数为空时,如何返回空结果?

问题描述 投票:1回答:1

我正在使用Spring Data JPA v1.10.2并且有一个用例:

ClientDao.java

List<Client> getClientsByUnitsIn(@NonNull Collection<Unit> units);

此方法生成如下所示的SQL查询:

SELECT * FROM clients WHERE units in (?1)

当我为存储库方法添加@Query注释时有类似的情况:

@Query("SELECT c FROM Client c WHERE c.unit IN (?1)")
List<Client> getSpecificClients(@NonNull Collection<Unit> units)

但在许多情况下,参数units可能是空的。在这种情况下,该方法应返回空结果,但它只是失败并显示有关错误SQL语句的消息。

我使用了一种解决方法:向存储库添加一个默认方法,如下所示:

default List<Client> getSpecificClientsOrEmpty(@NonNull Collection<Unit> units){
    if (units.isEmpty) {
        return emptyList();
    }
    return getSpecificClients(units);
}

但我不喜欢这种解决方法:

  • 我必须为每个案例创建一个额外的方法
  • 我必须检查只有默认方法在代码中使用,因为没有编译时检查,如果我错过了一些使用,我得到一个运行时异常。

有人有更好的解决方案吗?

java spring jpa spring-data
1个回答
2
投票

1)使用getSpecificClients()存储库实现中的样板代码编写您自己的查询:

public List<Client> getSpecificClients(@NonNull Collection<Unit> units){
    if (units.isEmpty()) {
        return emptyList();
    }
    return em.createQuery("SELECT c FROM Client c WHERE c.unit IN (?1)", Unit.class)
             .setParameter(1, units)
             .getResultList();  
}

如果这个预处理在您的存储库中是一个不常见的要求,那么这种方式应该受到青睐。 这是一种冗长的方式,但对于少数案例来说仍然可以接受。

2)用AOP横向进行。 定义Aspect以在您需要的每种方法之前执行此处理:

if (units.isEmpty) {
    return emptyList();
}

请注意,只有在预处理要求足够频繁发生时才应使用这种方式,因为它会增加应用程序的复杂性和一般设置。

3)您可以在基本接口存储库中创建一个通用的默认方法,该存储库接受Function作为参数,以便能够将任何方法执行的方法传递给该方法:

@SuppressWarnings("unchecked")
default<T, U> List<U> selectWithIn(Collection<T> valueForInClause, Function<Collection<T>, List<U>> function) {
    if (valueForInClause.isEmpty()) {
        return new ArrayList<U>();
    }
    return function.apply(valueForInClause);
}

ClientDAO课程中你仍然会有这个:

@Query("SELECT c FROM Client c WHERE c.unit IN (?1)")
List<Client> getSpecificClients(@NonNull Collection<Unit> units)

在DAO的客户端代码中,您可以通过以下方式调用selectWithIn()方法:

private ClientDAO clientDAO;
...
List<Unit> units = ...;
List<Client> clients = clientDAO.selectWithIn(units, (o) -> clientDAO.getSpecificClients(o));

它不是太冗长,它省略了一些代码行,但我不喜欢这种方式,因为它对DAO客户端类进行了一些更复杂的单元测试。

© www.soinside.com 2019 - 2024. All rights reserved.