使用 @Query JPA 注释将空参数传递给本机查询
Posted
技术标签:
【中文标题】使用 @Query JPA 注释将空参数传递给本机查询【英文标题】:Passing a null parameter to a native query using @Query JPA annotation 【发布时间】:2017-08-06 08:58:53 【问题描述】:在 Spring Boot 应用程序中,我有一个在 postgresql 服务器上执行的 SQL 查询,如下所示:
@Query(value = "select count(*) from servers where brand= coalesce(?1, brand) " +
"and flavour= coalesce(?2, flavour) ; ",
nativeQuery = true)
Integer icecreamStockCount(String country, String category);
然而,
执行该方法时出现以下错误:
ERROR: COALESCE types bytea and character varying in PostgreSQL
如何将 String value = null 传递给查询?
**注意:** 我发现我的问题与 JPA Query to handle NULL parameter value 不同
【问题讨论】:
我不知道这是否可能。如果某些输入为空,我会尝试创建单独的查询。 FWIW 没有 JPA@Query
注释。那是春天。
你可以把coalesce改成case when then else end
,比如"select count(*) from servers where brand = (case when ?1 = 'undefined' then brand else ?1::bytea) "
【参考方案1】:
你不需要合并,试试这个
@Query("select count(*) from servers where (brand = ?1 or ?1 is null)" +
" and (flavour = ?2 or ?2 is null)")
Integer icecreamStockCount(String country, String category);
【讨论】:
@Jodiug,你检查了吗?这是 TS 自带的问题。 删除了我的评论。从我的小实验看来,只要只有一个子句使用数据库中的数据,OR
就可以执行。所以?1 = 3 OR x = ?1
可以被索引但?1 = x OR x = 22
不能被索引。因此,您的答案根据该规则起作用。我的错!【参考方案2】:
Hibernate 5.0.2 之前不允许空参数。 见https://hibernate.atlassian.net/browse/HHH-9165 以及对https://www.postgresql.org/message-id/6ekbd7dm4d6su5b9i4hsf92ibv4j76n51f@4ax.com的回复
【讨论】:
【参考方案3】:如果你真的需要使用native query,就会出现问题,因为它是一项尚未实现的改进,请参阅hibernate。如果您不需要使用 native,您可以使用 (where ?1 is null or field like ?1)
。假设您确实需要 native,
您可以通过将其设置为空然后调用存储库来处理字符串,这将是这样的:
@Query(value = "select count(*) from servers where (?1 like '' or brand like ?1) " +
"and (?2 like '' or flavour like ?2)",
nativeQuery = true)
Integer icecreamStockCount(String country, String category);
对于本机查询情况,总是有 javax.persistence.EntityManager
bean 作为选项,我推荐它而不是以前的方法。在这里,您可以按照您想要的方式附加到您的查询中,如下所示:
String queryString = "select count(*) from servers ";
if (!isNull(country)) queryString += "where brand like :country";
Query query = entityManager.createNativeQuery(queryString);
if (!isNull(country)) query.setParameter("country", country);
return query.getResultList();
观察:
-
较新的版本改进了这种“+”连接字符串。但是您可以使用 StringBuilder 或 String Format 以您想要的方式构建您的 queryString,没关系。
小心SQL注入,setParameter方法避免了这种问题,更多信息见Sql Injection Baeldung
【讨论】:
【参考方案4】:当我遇到此错误时,我最终使用OR
和CAST
的组合来解决问题。
SELECT COUNT(*)
FROM servers
WHERE (?1 IS NULL OR brand = CAST(?1 AS CHARACTER VARYING))
AND (?2 IS NULL OR flavour = CAST(?2 AS CHARACTER VARYING))
即使 ?1
、?2
、brand
和 flavor
都是可为空的字段,这仍然有效。
请注意,将null
传递给?1
的意思是“所有服务器,不分品牌”,而不是“所有不带品牌的服务器”。对于后者,您可以使用IS DISTINCT FROM
,如下所示。
SELECT COUNT(*)
FROM servers
WHERE (CAST(?1 AS CHARACTER VARYING) IS NOT DISTINCT FROM brand)
AND (CAST(?2 AS CHARACTER VARYING) IS NOT DISTINCT FROM flavour)
最后,某些参数类型如Boolean
不能在SQL中从BYTEA
转换为BOOLEAN
,对于这些情况你需要双重转换:
SELECT COUNT(*)
FROM servers
WHERE (?1 IS NULL OR is_black = CAST(CAST(?1 AS CHARACTER VARYING) AS BOOLEAN))
在我看来,这是 Hibernate 中的一个问题,可以通过将 Java null
参数作为普通 SQL NULL
s 传递而不是将 null
解释为 BYTEA
类型的值来解决。
【讨论】:
【参考方案5】:所以这不是上述问题的确切答案,但我遇到了类似的问题,我想我会在这里添加它,对于那些遇到这个问题的人。
我使用的是本机查询,就我而言,它不是像上面那样的奇异值,但我传入了一个列表来匹配查询的这一部分:
WHERE (cm.first_name in (:firstNames) OR :firstNames is NULL)
我收到了bytea
错误,最后我能够发送一个空列表。
(null == entity.getFirstName()? Collections.emptyList() : entity.getFirstName())
在这种情况下,将空列表发送到解析器是可行的,而 null 则没有。
希望这可以为您节省一些时间。
【讨论】:
以上是关于使用 @Query JPA 注释将空参数传递给本机查询的主要内容,如果未能解决你的问题,请参考以下文章
将空值作为参数传递给方法时如何修复 NullPointerException [重复]
如何将空参数传递给 msdeploy powershell deploy 命令