【问题标题】:How to pass list of nested lists into JPA native query如何将嵌套列表的列表传递到 JPA 本机查询中
【发布时间】: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,在继续之前你必须将你的通用列表解析为一个字符串:)
  • 您好,谢谢您的回答。但是,当我尝试将它作为扁平字符串传递时,它也不起作用。

标签: java oracle spring-boot jpa


【解决方案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));

【讨论】:

    猜你喜欢
    • 2021-11-18
    • 2011-09-10
    • 2014-09-11
    • 2023-01-20
    • 2017-03-23
    • 2018-10-22
    • 2023-04-09
    • 2021-01-08
    相关资源
    最近更新 更多