Postgres & JPA 命名查询 - WHERE 中的任何 (*) 值
Posted
技术标签:
【中文标题】Postgres & JPA 命名查询 - WHERE 中的任何 (*) 值【英文标题】:Postgres & JPA named queries - any (*) value in WHERE 【发布时间】:2019-06-09 09:24:36 【问题描述】:我想为一些特定的 GET 案例编写过滤查询。
我现在正在做的是为每个案例编写单独的查询,这非常耗时。相反,我想编写一个大的命名查询,如果设置了过滤器,我可以在 WHERE 子句中输入一个值,否则为 ANY。 JPA可以做到这一点吗? 这是一个示例控制器,它通过特定的客户端 ID 返回付款:
public List<PaymentEntity> findAllByClientId(final int page, final int pageSize, final String fromDate,
final String toDate, final Long clientId)
Map<String, Object> parameters = new HashMap<>();
parameters.put("clientId", clientId);
return super.findWithNamedQueryPagination("PaymentEntity.findAllWithPaginationByClientId", parameters,
PaymentEntity.class, page, pageSize, fromDate, toDate);
这是属于命名查询:
SELECT i FROM PaymentEntity i WHERE i.clientContractData.client.id = :clientId AND i.createdAt BETWEEN :fromDate AND :toDate ORDER BY i.createdAt DESC
我现在想要的是能够像这样传递一个参数:
if(clientId == null)
parameters.put("clientId", "*");
else
parameters.put("clientId", clientId);
但现在我当然会收到类型错误:Parameter value [*] did not match expected type [java.lang.Long (n/a)]
实现这一目标的最佳方法是什么?我必须编写本机查询还是有命名查询的方法?
编辑澄清:上面的示例显示了一个类型为 Long
的查询,但我也需要使用 String
执行此操作。
【问题讨论】:
【参考方案1】:您可以尝试更改您的查询,例如:
WHERE (i.clientContractData.client.id = :clientId or :clientId = -1)
注意:我认为 JPA 中的引用可以达到 2 个级别,而这里有 3 个级别:
i.clientContractData.client.id
您可能需要在此处使用额外的显式连接
【讨论】:
你是说:clientId is null
吗?
我想由 OP 决定使用什么作为任何值
我编辑了这个问题。这是 Long 类型的一个很好的解决方案,但不幸的是我需要一个也适用于字符串的解决方案。对于级别 - 它使用 3 个级别 :) 我为这种情况编写了一些测试。
似乎 3-Level-Deep 引用确实是 WHERE 子句结合 OR 语句的问题。当我将客户端存储在付款中并这样做时,它可以工作:SELECT i FROM PaymentEntity i WHERE (:clientId IS NULL OR i.client.id = :clientId) AND i.createdAt BETWEEN :fromDate AND :toDate ORDER BY i.createdAt DESC
【参考方案2】:
更新查询,
SELECT i FROM PaymentEntity i WHERE
((i.clientContractData.client.id = :clientId and :clientId IS NOT NULL)
or (i.clientContractData.client.id IS NOT NULL AND :clientId IS NULL))
AND i.createdAt BETWEEN :fromDate AND :toDate ORDER BY i.createdAt DESC
如果 clientId 为 null,则发送 null 值:
if(clientId == null)
parameters.put("clientId", null);
else
parameters.put("clientId", clientId);
对于更复杂的情况,您使用 rsql-jpa-specification 项目:
https://github.com/perplexhub/rsql-jpa-specification
【讨论】:
这看起来是一个很好的长字符串解决方案,我今天会试试这个并回复你!虽然当我有很多值要过滤时查询会变得很长:) 不幸的是,这只会给我PaymentEntity
也有相关clientContractData
的结果,但默认情况下我需要所有条目。其实我不明白为什么这不起作用:SELECT i FROM PaymentEntity i WHERE (:clientId IS NULL OR i.clientContractData.client.id = :clientId) AND i.createdAt BETWEEN :fromDate AND :toDate ORDER BY i.createdAt DESC
。这也只返回带有 clientcontractdata 的付款。也许这是由于@Maciej Kowalski 提到的 3-Level-Deep 嵌套?以上是关于Postgres & JPA 命名查询 - WHERE 中的任何 (*) 值的主要内容,如果未能解决你的问题,请参考以下文章
如何在 jpa 查询中调用 postgres position() 函数
Postgres Interval 不适用于本机 Spring 数据 JPA 查询
Spring Data JPA 方法或查询以使用 Postgres 列执行算术运算
如何根据postgres的jsonb列的where条件(无本机查询)使用jpa在spring boot中选择数据?