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

vm0i2vca  于 2024-01-05  发布在  Java
关注(0)|答案(4)|浏览(355)

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

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

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

  1. |product_spec_id | commodity_spec_id|
  2. |----------------|------------------|
  3. |1683 |1681 |
  4. |1692 |1693 |
  5. |1692 |1681 |
  6. |1692 |1687 |
  7. |1692 |1864 |
  8. |1860 |1681 |
  9. |1868 |1681 |
  10. |1868 |1864 |

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

  1. SELECT ps.product_spec_id, commodities
  2. FROM (
  3. SELECT
  4. product_spec_id,
  5. array_agg(commodity_spec_id) AS commodities
  6. FROM system.product_spec_entry
  7. GROUP BY product_spec_id) ps
  8. WHERE Cast(ARRAY [1681, 1864] as BIGINT[]) <@ Cast(ps.commodities as BIGINT[]);


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

  1. String query = "SELECT ps.product_spec_id " +
  2. "FROM ( " +
  3. " SELECT " +
  4. " product_spec_id, " +
  5. " array_agg(commodity_spec_id) AS commodities " +
  6. " FROM system.product_spec_entry " +
  7. " GROUP BY product_spec_id) ps " +
  8. "WHERE CAST(ARRAY[:commoditySpecIds] AS BIGINT[]) <@ CAST(ps.commodities AS BIGINT[])";
  9. List<Long> commoditySpecsIds = commoditySpecs.stream().map(Spec::getId).collect(Collectors.toList());
  10. List<BigInteger> productSpecIds = em.createNativeQuery(query).setParameter("commoditySpecIds", commoditySpecsIds)
  11. .getResultList();


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

q5lcpyga

q5lcpyga1#

从SQL中删除array[...]

  1. WHERE CAST(:commoditySpecIds AS BIGINT[])

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

  1. "{1,2,3,4}"


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

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


然后将其传递给混淆层:

  1. setParameter("commoditySpecIds", literal)

展开查看全部
pinkon5k

pinkon5k2#

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

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

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

cgvd09ve

cgvd09ve3#

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

  1. // unwrap hibenate session
  2. final Session hibernateSession = em.unwrap(Session.class);
  3. // create you SQL query in hibernate style
  4. final SQLQuery sqlQuery = hibernateSession.createSQLQuery(sql);

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

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


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

展开查看全部
pbpqsu0x

pbpqsu0x4#

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

  1. final var commoditySpecs = List.of(new Spec(1681), new Spec(1864));
  2. final Long[] commoditySpecsIds = commoditySpecs.stream().map(Spec::getId).toArray(Long[]::new);
  3. final List<Integer> resultList = entityManager
  4. .createNativeQuery("""
  5. SELECT ps.product_spec_id
  6. FROM (
  7. SELECT
  8. product_spec_id,
  9. array_agg(commodity_spec_id) AS commodities
  10. FROM product_spec_entry
  11. GROUP BY product_spec_id) ps
  12. WHERE Cast(:commoditySpecIds as BIGINT[]) <@ Cast(ps.commodities as BIGINT[]);
  13. """)
  14. .setParameter("commoditySpecIds", commoditySpecsIds)
  15. .getResultList();
  16. for (final var o : resultList) {
  17. System.out.println(o);
  18. }

字符串
指纹

  1. 1692
  2. 1868

展开查看全部

相关问题