java 将数组参数绑定到本机查询

vm0i2vca  于 4个月前  发布在  Java
关注(0)|答案(4)|浏览(70)

我有一个表product_spec_entry,其中包含以下列:

  • 产品规格ID
  • 商品规格ID

对于一个product_spec_id,可以是多个commodity_spec_id,例如:

|product_spec_id | commodity_spec_id|
|----------------|------------------|
|1683            |1681              |
|1692            |1693              |
|1692            |1681              |
|1692            |1687              |
|1692            |1864              |
|1860            |1681              |
|1868            |1681              |
|1868            |1864              |

字符串
我想得到所有product_spec_id,所有commodity_spec_id都作为参数传递。
我写了下一个查询:

SELECT ps.product_spec_id, commodities
FROM (
       SELECT
         product_spec_id,
         array_agg(commodity_spec_id) AS commodities
       FROM system.product_spec_entry
       GROUP BY product_spec_id) ps
WHERE Cast(ARRAY [1681, 1864] as BIGINT[]) <@ Cast(ps.commodities as BIGINT[]);


它工作正常,并返回预期结果:
product_spec_id = 1692,1868
我尝试将此查询用于JPA原生查询:

String query = "SELECT ps.product_spec_id " +
                "FROM ( " +
                "       SELECT " +
                "         product_spec_id, " +
                "         array_agg(commodity_spec_id) AS commodities " +
                "       FROM system.product_spec_entry " +
                "       GROUP BY product_spec_id) ps " +
                "WHERE CAST(ARRAY[:commoditySpecIds] AS BIGINT[]) <@ CAST(ps.commodities AS BIGINT[])";
List<Long> commoditySpecsIds = commoditySpecs.stream().map(Spec::getId).collect(Collectors.toList());

List<BigInteger> productSpecIds = em.createNativeQuery(query).setParameter("commoditySpecIds", commoditySpecsIds)
                .getResultList();


它不起作用,因为我得到的是记录数组(ARRAY[(1692, 1868)]),而不是bigint数组(ARRAY[1692, 1868])。
我应该如何绑定数组参数到我的查询?也许我可以使用更简单的查询。

q5lcpyga

q5lcpyga1#

从SQL中删除array[...]

WHERE CAST(:commoditySpecIds AS BIGINT[])

字符串
然后将ID列表作为字符串传递,如下所示:

"{1,2,3,4}"


Lists的默认toString()通常返回类似于:"[1,2,3]"的内容,所以你可以这样做:

String literal = commoditySpecsIds.toString();
literal = "{" + literal.substring(1,literal.length() - 1) + "};


然后将其传递给混淆层:

setParameter("commoditySpecIds", literal)

pinkon5k

pinkon5k2#

我也是一样的情况,希望@VladMihalcea能帮助我们
编辑
我想用JPA来做。在阅读setParameter的实现之后,我发现了一些类似于UserType的东西,即TypedParameterValue。
当您使用

setParameter("commoditySpecIds", new TypedParameterValue(IntArrayType.INSTANCE, commoditySpecsIds))

字符串
其中IntArrayType. BIDANCE来自Vlad Mihalcea提供的“hibernate-types”库。请注意,“commoditySpecsIds”必须是数组,而不是Collection。
希望有帮助

cgvd09ve

cgvd09ve3#

对于您的情况,其他方法是打开JPA提供程序会话,并使用JPA提供程序API中的一些方法。
如果你正在使用Hibernate,你可以这样做:

// unwrap hibenate session
final Session hibernateSession = em.unwrap(Session.class);

// create you SQL query in hibernate style
final SQLQuery sqlQuery = hibernateSession.createSQLQuery(sql);

字符串
然后也使用hibernate API设置参数

final Type customType = new CustomType(new ArrayTypeUser());
sqlQuery.setParameter("commoditySpecIds", value, customType);


其中“ArrayTypeUser”是一个自定义类型,它将PostgreSQL数组类型Map到Java数组类型。
这不是最好的解决方案,但由于您已经在使用本机查询,因此对于这种特殊情况,最好的解决方案可能是跳过JPA标准API,使用JPA提供的API。

pbpqsu0x

pbpqsu0x4#

其实答案很简单--你应该在这里使用Array而不是List。

final var commoditySpecs = List.of(new Spec(1681), new Spec(1864));
final Long[] commoditySpecsIds = commoditySpecs.stream().map(Spec::getId).toArray(Long[]::new);
final List<Integer> resultList = entityManager
        .createNativeQuery("""
                           SELECT ps.product_spec_id
                           FROM (
                                    SELECT
                                        product_spec_id,
                                        array_agg(commodity_spec_id) AS commodities
                                    FROM product_spec_entry
                                    GROUP BY product_spec_id) ps
                           WHERE Cast(:commoditySpecIds as BIGINT[]) <@ Cast(ps.commodities as BIGINT[]);
                           """)
        .setParameter("commoditySpecIds", commoditySpecsIds)
        .getResultList();
for (final var o : resultList) {
    System.out.println(o);
}

字符串
指纹

1692
1868

相关问题