如何将嵌套列表的列表传递到 JPA 本机查询中
Posted
技术标签:
【中文标题】如何将嵌套列表的列表传递到 JPA 本机查询中【英文标题】:How to pass list of nested lists into JPA native query 【发布时间】:2021-08-26 11:27:26 【问题描述】:我需要创建一个与以下示例相关的 JPA 原生查询:
select * from inventory where (server, product) in (('server1','product1'), ('server2','product2'), ('server1','product3'));
我创建了一个原生查询:
@Query(
value = "select server, product from inventory where (server, product) in (:myList)",
nativeQuery = true
)
List<Product> getProducts(List<List<String>> myList);
但是当我将列表列表作为参数传递时:
List<List<String>> myList= Arrays.asList(
Arrays.asList("server1","product1"),
Arrays.asList("server2","product2"),
Arrays.asList("server1","product3")
);
List<Product> products = myRepository.getProducts(myList);
我收到一个错误
java.sql.SQLSyntaxErrorException: ORA-00920: invalid relational operator
我使用 Oracle 数据库。请告诉我,我做错了什么?
这个问题不是关于将平面列表传递到本机查询中以按 1 列过滤数据库结果(这很好),而是如何传递嵌套列表列表 进入查询按 2 列过滤数据库结果。
【问题讨论】:
你好@Ula,在继续之前你必须将你的通用列表解析为一个字符串:) 您好,谢谢您的回答。但是,当我尝试将它作为扁平字符串传递时,它也不起作用。 【参考方案1】:已知缺少括号或逗号会引发此错误。
java.sql.SQLSyntaxErrorException: ORA-00920: invalid relational operator
所以我认为 将您的通用列表解析为字符串。
请注意将您的数据解析为 String ,我建议您使用 String 作为 getProducts 方法的参数,否则您应该先解析该函数中的列表,然后再将其添加到查询中:
这是一个如何解析通用列表的示例:
String myListToStr = "";
for(List<String> list : myList)
myListToStr += "(\"" + String.join("\",\"", list) + "\")";
myListToStr = myListToStr.replace(")(", "),(");
System.out.println(myListToStr);
结果: ("server1","product1"),("server2","product2"),("server1","product3")
正是您在这种情况下所需要的。
希望您对这个解决方案感到满意。如果它确实解决了您的问题,请务必将其标记为答案!
【讨论】:
您好,谢谢您的回答。但是,当我尝试将它作为扁平字符串传递时,它也不起作用。【参考方案2】:我找到了一个可行的解决方案。我不得不对 Specification 和 CriteriaBuilder 使用动态查询。
我创建了一个模型类:
public class SrvProdTuple
String server;
String product;
// + getters
规格:
public class mySpecification
public static Specification<Product> getProducts(
List<SrvProdTouple> myList
)
return (root, query, cb) ->
List<Predicate> predicates = new ArrayList<>();
myList.forEach(srvProdTouple ->
List<Predicate> srvProdPredicates = new ArrayList<>();
srvProdPredicates.add(
cb.equal(root.get("server"), srvProdTouple.getServer())
);
srvProdPredicates.add(
cb.equal(root.get("product"), srvProdTouple.getProduct())
);
predicates.add(cb.and(srvProdPredicates.toArray(new Predicate[])));
);
return cb.or(predicates.toArray(new Predicate[]));
;
及用法(我用了一个JPA方法findAll(Specification specification)):
List<SrvProdTouple> myList= Arrays.asList(
new SrvProdTouple("server1","product1"),
new SrvProdTouple("server2","product2"),
new SrvProdTouple("server1","product3")
);
List<Product> products = myRepository.findAll(mySpecification.getProducts(myList));
【讨论】:
以上是关于如何将嵌套列表的列表传递到 JPA 本机查询中的主要内容,如果未能解决你的问题,请参考以下文章
如何在本机查询中使用 NVL 或 COALESCE 获取 Spring Data JPA 中的值列表