java 方法命名中的 Spring 'NOT IN' 没有按预期工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33271099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 21:27:11  来源:igfitidea点击:

Spring 'NOT IN' in method naming does not work as it expected

javaspringhibernatespring-bootspring-data-jpa

提问by Oleh Dokuka

Question

问题

Is it bug, or it just my fail? Can you explain me what is wrong?

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

Code

代码

I have created simple JPARepository

我创建了简单的JPARepository

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


    Collection<User> findByIdNotIn(Collection<Long> users);
}

It looks correct. And it works correct if usersis not empty. But otherwise it works incorrect:

看起来是正确的。如果users不为空,它就可以正常工作。但否则它工作不正确:

result = userRepository.findByIdNotIn([]);

It returns empty result, but it should be equals to result of findAllmethod call.

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

userRepository.findByIdNotIn([]).equals(userRepository.findAll());

Also

To check result I have added @Queryannotation to method

为了检查结果,我@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);
}

And in this case expected result was correct. Also I have tried write query using native Hibernate CriteriaBuilder

在这种情况下,预期结果是正确的。我也尝试过使用本机 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();

And in this case expected result was correct too.

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

Additional Info

附加信息

Result Hibernate queries: Correct result (using @Queryannotation):

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

Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in  ()

Incorrect result(using method naming):

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

Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in  (?)

My conclusion

我的结论

It looks like a Spring JPA bug

它看起来像一个 Spring JPA 错误

New Additional Info

新的附加信息

I spent a day in debuging spring-data-jpasource code, and I found that the problems occurs in org.springframework.data.jpa.provider.PersistenceProviderin method potentiallyConvertEmptyCollectionfor HIBERNATE

调试了一天spring-data-jpa源码,发现问题出在org.springframework.data.jpa.provider.PersistenceProviderin method potentiallyConvertEmptyCollectionfor HIBERNATE

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

When collection is empty this function return nullvalue. But I have found, if this value replaced (at runtime) on empty collection again then the final result would be correct!!!

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

HAVE YOU ANY IDEA ABOUT THIS?!

你对这个有什么想法吗?!

采纳答案by TheBakker

From JPA Specification 4.6.9 In Expressions :

从 JPA 规范 4.6.9 在表达式中:

There must be at least one element in the comma separated list that defines the set of values for the IN expression. If the value of a state_field_path_expression or in_item in an IN or NOT IN expression is NULL or unknown, the value of the expression is unknown.

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

So Spring JPA is just following JPA specification, even if, as you said, one could expect that there would be no restriction.

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

Best to just do the check in your business before calling the right repository method.

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