【发布时间】:2019-05-30 07:33:18
【问题描述】:
我有一个 Spring Boot 应用程序并使用 Spring Data JPA 来查询 MySQL 数据库。
我需要得到一个用一些参数过滤的课程列表。
我通常使用语法param IS NULL or (/*do something with param*/),这样如果参数为空,它就会忽略它。
使用简单的数据类型我没有问题,但是当涉及到对象列表时,我不知道如何检查 NULL 值。如何检查以下查询中的?3 参数是否为NULL?
@Query("SELECT DISTINCT c FROM Course c\n" +
"WHERE c.courseDate < CURRENT_TIME\n" +
"AND (?1 IS NULL OR (c.id NOT IN (3, 4, 5)))\n" +
"AND (?2 IS NULL OR (c.title LIKE ?2 OR c.description LIKE ?2))\n" +
"AND ((?3) IS NULL OR (c.category IN ?3)) ")
List<Course> getCoursesFiltered(Long courseId, String filter, List<Category> categories);
错误是:
无法提取结果集; SQL [不适用];嵌套异常是 org.hibernate.exception.DataException: could not extract ResultSet[SQL: 1241, 21000]
在堆栈跟踪中我可以看到:
原因:java.sql.SQLException:操作数应包含 1 列
如果我的列表包含 3 个元素,则确实生成的查询将是 ... AND ((?3, ?4, ?5) IS NULL OR (c.category IN (?3, ?4, ?5)))。但是IS NULL 不能应用于多个元素(如果我的列表只包含一个元素,则查询可以正常工作)。
我尝试了size(?3) < 1、length(?3) < 1、(?3) IS EMPTY 等,但仍然没有运气。
【问题讨论】:
-
您需要多少细粒度的查询控制?如果您使用的是 Spring Boot,您是否考虑过使用基于方法名称自动生成的 CRUD 方法?这样,您可以在参数上使用 @Nullable 注释,它可能开箱即用。见docs.spring.io/spring-data/jpa/docs/current/reference/html/…
-
否则,我相信在 MySQL 中,说“X 在 (NULL) 中的位置”是有效的语法,所以我认为您上面的查询应该有效。您的问题似乎在于提取 ResultSet,而不是运行查询。您能否为您的课程类添加完整的代码以及实体映射和您遇到的错误的完整堆栈跟踪?
-
(当然,虽然这可能不是你想要的答案,但最简单的解决方案是有两种单独的查询方法,一种检查类别,另一种不检查,还有一个委托在 Java 代码中检查您的类别列表并根据它是否为空来调用适当的查询的方法,即如果它为空,则根本不将其包含在查询中)
-
感谢马特,我已经使用基于方法名称的查询来满足其他需求,但实际上我在这里谈到的查询已经针对示例进行了简化,不能那样做。顺便说一下
where X in (NULL)按预期工作,是(?3) IS NULL语句导致了问题。我的Course类和实体映射非常基础,没什么特别的。我确实从管理器类中调用了存储库方法,我可以按照你的建议在那里做一些技巧,但我很确定有一种更清洁的方法来做到这一点:)
标签: sql jpa spring-data-jpa spring-data hql