方法命名中的Spring'NOT IN'不能像预期的那样工作

Ole*_*uka 7 java spring hibernate spring-data-jpa spring-boot

它是错误,还是我的失败?你能解释一下我有什么问题吗?

我创建了简单的JPARepository

@Repository
interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);


    Collection<User> findByIdNotIn(Collection<Long> users);
}
Run Code Online (Sandbox Code Playgroud)

看起来很正确.如果users不是空的话,它的工作正确.但否则它工作不正确:

result = userRepository.findByIdNotIn([]);
Run Code Online (Sandbox Code Playgroud)

它返回空结果,但它应该等于findAll方法调用的结果.

userRepository.findByIdNotIn([]).equals(userRepository.findAll());
Run Code Online (Sandbox Code Playgroud)

为了检查结果,我@Query在方法中添加了注释

@Repository
interface UserRepository extends JpaRepository<User, Long> {
    User findByName(String name);

    @Query('SELECT u FROM User u WHERE u.id NOT IN ?1')
    Collection<User> findByIdNotIn(Collection<Long> users);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,预期结果是正确的.我也试过使用原生Hibernate编写查询CriteriaBuilder

CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = builder.createQuery(User.class);
Root<User> root = query.from(User.class);

query.where(builder.not(root.get("id").in([])));
result = entityManager.createQuery(query.select(root)).getResultList();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,预期结果也是正确的.

附加信息

结果Hibernate查询:更正结果(使用@Query注释):

Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in  ()
Run Code Online (Sandbox Code Playgroud)

结果不正确(使用方法命名):

Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in  (?)
Run Code Online (Sandbox Code Playgroud)

我的结论

它看起来像一个Spring JPA bug

新的附加信息

我花了一天时间来描述spring-data-jpa源代码,我发现问题发生在HIBERNATE的org.springframework.data.jpa.provider.PersistenceProvider方法potentiallyConvertEmptyCollection

@Override
        public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
            return collection == null || collection.isEmpty() ? null : collection;
        }
Run Code Online (Sandbox Code Playgroud)

当集合为空时,此函数返回null值.但我发现,如果这个值再次(在运行时)替换空集合,那么最终结果将是正确的!

你有什么想法吗?!

The*_*ker 6

从JPA Specification 4.6.9 In Expressions:

逗号分隔列表中必须至少有一个元素定义IN表达式的值集.如果IN或NOT IN表达式中state_field_path_expression或in_item的值为NULL或未知,则表达式的值未知.

所以Spring JPA只是遵循JPA规范,即使如你所说,人们可以预期不会有任何限制.

在调用正确的存储库方法之前,最好只检查您的业务.