如何使用Spring Data JPA查询更新PostgreSQL中的JSONB列

5

我有如下控制器

@RequestMapping(value = "/update/{tableId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE,
            consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity updateItemQty (@PathVariable Long tableId, @RequestBody AddItemsRequestBody requestBody,
                                              HttpServletRequest request){
        try {
            String addedBy = getUserName(request);
            Float ItemQuantity = requestBody.getItemQuantity();
            LocalDateTime dateTimeAdded = LocalDateTime.now();
            String subId = requestBody.getItemSubId();
            ArrayList<ItemAdditionDetails> updatedAdditionDetails = new ArrayList<>();

        ItemAdditionDetails newItemAdditionDetails = new ItemAdditionDetails();
        newItemAdditionDetails.setIncreamentCount(ItemQuantity);
        newItemAdditionDetails.setAddedDateTime(dateTimeAdded);
        newItemAdditionDetails.setAddedBy(addedBy);

        updatedAdditionDetails.add(newItemAdditionDetails);

// Here i am fetching a JSON-B column that returns an array of json objects from Postgress DB  
     ItemInventoryService.findByItemSubId(subId).getItemsInventoryAdditionDetails().forEach((el) -> {
                updatedAdditionDetails.add(el);
            });

        itemInventoryService.updateItemsAdditionDetails(subId,updatedAdditionDetails);

        return new ResponseEntity("Updated", HttpStatus.CREATED);
    }catch (Exception ex){
        return new ResponseEntity(ex, HttpStatus.INTERNAL_SERVER_ERROR);
    }

}

如果我移除/注释掉

ItemInventoryService.findByItemSubId(subId).getItemsInventoryAdditionDetails().forEach((el) -> {
                updatedAdditionDetails.add(el);
            });

我不将获取的结果添加到新的updatedAdditionDetails(类型为ArrayList)中时,数据库会成功更新。 否则我会得到以下错误:
ERROR: column \"itemsinventory_addtion_details\" is of type jsonb but expression is of type record Hint: You will need to rewrite or cast the expression. Position
在我的Repository中有以下查询:
@Transactional
    @Modifying
    @Query(value = "UPDATE items_inventory  SET itemsinventory_addtion_details = :updatedAdditionDetails WHERE item_subid = :subId", nativeQuery = true)
    Integer updateItemsAdditionDetails(@Param("subId") String subId, @Param("updatedAdditionDetails") List<ItemAdditionDetails> updatedAdditionDetails);

我尝试了JPA的方法,如下:

 @Query(value = "UPDATE ItemsInventory items  SET items.itemsInventoryAdditionDetails = :updatedAdditionDetails WHERE items.itemSubId = :subId")

很不幸,这也导致了相同的错误。 非常感谢任何帮助。 提前致谢。


你能添加你的JPA bean定义吗?这里也许会有帮助:https://dev59.com/WFUM5IYBdhLWcg3wF9PZ - Pawel Zieminski
抱歉,刚刚注意到您没有在此处使用实体 Bean。不过,请查看上面的链接。 - Pawel Zieminski
2个回答

5

错误的原因

PostgreSQL 错误信息如下:

错误: 列 "itemsinventory_addtion_details" 的类型为 jsonb,但表达式的类型为 record\n 提示: 你需要重新编写或者转换表达式。\n 位置

这个错误是由于 List 被这样传递造成的:

UPDATE
    ItemsInventory items
SET
    items.itemsInventoryAdditionDetails = (?, ?, ?, .., ?)
WHERE
    items.itemSubId = ?

默认情况下,使用Hibernate的Spring Data JPA不知道如何处理JSON类型。因此,您需要使用自定义的Hibernate Type,例如JsonBinaryType,它是由Hibernate Types项目提供的。

Maven 依赖项

首先,您需要添加 Hibernate Types 依赖项:

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

当你将hibernate-types.version Maven属性设置为最新版本后,这个依赖项将从Maven Central下载。

显式设置Hibernate类型

你无法使用Spring的@Query注解,因为你无法显式地设置Hibernate类型。

因此,你需要添加一个自定义的Spring Data JPA Repository实现,并包含以下方法:

public int updateItemsAdditionDetails(
    String subId, 
    List<ItemAdditionDetails> updatedAdditionDetails) {
    return entityManager.createNativeQuery(
        "UPDATE items_inventory  SET itemsinventory_addtion_details = :updatedAdditionDetails WHERE item_subid = :subId")
    .unwrap(NativeQuery.class)
    .setParameter("updatedAdditionDetails", updatedAdditionDetails, JsonBinaryType.INSTANCE)
    .setParameter("subId", subId)
    .executeUpdate();
}

就是这样!


感谢您的输入。该查询在上述实现中返回空值。在我的ItemInventoryRepositoryCustom中: int updateItemsAdditionDetails(String subId, List<ItemAdditionDetails> updatedAdditionDetails); 在我的ItemInventoryRepositoryImpl中,我已经实现了上述建议的方法。 最后,我的JPA repo public interface ItemInventoryRepository extends JpaRepository<ItemsInventory, Long>, ItemInventoryRepositoryCustom{} 该查询返回 "message": null, "suppressed": [], "localizedMessage": null 我在这里做错了什么? - ShibenDutta
不用谢。我相信你现在会找到解决方案的。只是调试问题的事情。 - Vlad Mihalcea

0

我发现另一个选项是在将集合提供给查询之前将其序列化为字符串:

@Transactional
@Modifying
@Query(value = "UPDATE items_inventory  SET itemsinventory_addtion_details = :updatedAdditionDetails WHERE item_subid = :subId", nativeQuery = true)
Integer updateItemsAdditionDetails(
    @Param("subId") String subId,
    @Param("updatedAdditionDetails") String updatedAdditionDetails
                                  /* ^^^^^^ here */
);

default Integer updateItemsAdditionDetails(
    @Param("subId") String subId,
    @Param("updatedAdditionDetails") List<ItemAdditionDetails> updatedAdditionDetails
) {
    String updatedAdditionDetailsStr = new com.fasterxml.jackson.databind
        .ObjectMapper().writeValueAsString(updatedAdditionDetails);

    return updateItemsAdditionDetails(subId, updatedAdditionDetailsStr);
}

Postgres似乎可以隐式地将其转换为jsonb而没有问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接