方法命名中的 Spring 'NOT IN' 未按预期工作
Spring 'NOT IN' in method naming does not work as it expected
问题
这是错误,还是我的失败?你能解释一下哪里出了问题吗?
代码
我创建了简单的 JPARepository
@Repository
interface UserRepository extends JpaRepository<User, Long> {
User findByName(String name);
Collection<User> findByIdNotIn(Collection<Long> users);
}
看起来是正确的。如果 users
不为空,它可以正常工作。但否则它工作不正确:
result = userRepository.findByIdNotIn([]);
它 return 是空结果,但它应该等于 findAll
方法调用的结果。
userRepository.findByIdNotIn([]).equals(userRepository.findAll());
还有
为了检查结果,我在方法中添加了 @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);
}
在这种情况下,预期结果是正确的。
我也尝试使用本机 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();
在这种情况下,预期结果也是正确的。
附加信息
Hibernate 查询结果:
正确结果(使用 @Query
注释):
Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in ()
不正确的结果(使用方法命名):
Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in (?)
我的结论
它看起来像一个 Spring JPA 错误
新附加信息
调试了一天spring-data-jpa
源码,发现问题出在方法potentiallyConvertEmptyCollection
for org.springframework.data.jpa.provider.PersistenceProvider
休眠
@Override
public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
return collection == null || collection.isEmpty() ? null : collection;
}
当集合为空时此函数return null
值。
但是我发现,如果这个值再次在空集合上替换 (at runtime) 那么最终结果将是正确的!!!
你对此有什么想法吗?!
来自 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.
所以 Spring JPA 只是遵循 JPA 规范,即使如您所说,人们可以期望没有限制。
最好在调用正确的存储库方法之前检查您的业务。
问题
这是错误,还是我的失败?你能解释一下哪里出了问题吗?
代码
我创建了简单的 JPARepository
@Repository
interface UserRepository extends JpaRepository<User, Long> {
User findByName(String name);
Collection<User> findByIdNotIn(Collection<Long> users);
}
看起来是正确的。如果 users
不为空,它可以正常工作。但否则它工作不正确:
result = userRepository.findByIdNotIn([]);
它 return 是空结果,但它应该等于 findAll
方法调用的结果。
userRepository.findByIdNotIn([]).equals(userRepository.findAll());
还有
为了检查结果,我在方法中添加了 @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);
}
在这种情况下,预期结果是正确的。
我也尝试使用本机 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();
在这种情况下,预期结果也是正确的。
附加信息
Hibernate 查询结果:
正确结果(使用 @Query
注释):
Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in ()
不正确的结果(使用方法命名):
Hibernate: select user0_.id as id1_7_, user0_.name as name2_7_ from User user0_ where user0_.id not in (?)
我的结论
它看起来像一个 Spring JPA 错误
新附加信息
调试了一天spring-data-jpa
源码,发现问题出在方法potentiallyConvertEmptyCollection
for org.springframework.data.jpa.provider.PersistenceProvider
休眠
@Override
public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
return collection == null || collection.isEmpty() ? null : collection;
}
当集合为空时此函数return null
值。
但是我发现,如果这个值再次在空集合上替换 (at runtime) 那么最终结果将是正确的!!!
你对此有什么想法吗?!
来自 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.
所以 Spring JPA 只是遵循 JPA 规范,即使如您所说,人们可以期望没有限制。
最好在调用正确的存储库方法之前检查您的业务。