Tengo el siguiente controlador
@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); } }Si elimino/comento
ItemInventoryService.findByItemSubId(subId).getItemsInventoryAdditionDetails().forEach((el) -> { updatedAdditionDetails.add(el); });Es decir, no agrego el resultado obtenido a los nuevos AdditionDetails actualizados (de tipo ArrayList), la base de datos se actualiza correctamente. De lo contrario, aparece el siguiente error:
ERROR : la columna \"itemsinventory_addtion_details\" es de tipo jsonb pero la expresión es de tipo record\n Sugerencia: deberá reescribir o convertir la expresión.\n Posición
En mi Repositorio tengo la siguiente consulta
@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);Lo he probado de la manera JPA de la siguiente manera:
@Query(value = "UPDATE ItemsInventory items SET items.itemsInventoryAdditionDetails = :updatedAdditionDetails WHERE items.itemSubId = :subId")Desafortunadamente, esto ha obtenido el mismo error. Cualquier ayuda en esto es muy apreciada. Gracias por adelantado.
El error de PostgreSQL tiene el siguiente aspecto:
ERROR: la columna "itemsinventory_addtion_details" es de tipo jsonb pero la expresión es de tipo record\n Sugerencia: deberá reescribir o convertir la expresión.\n Posición
Este error se produce porque la List se pasa así:
UPDATE ItemsInventory items SET items.itemsInventoryAdditionDetails = (?, ?, ?, .., ?) WHERE items.itemSubId = ? De forma predeterminada, Spring Data JPA, que usa Hibernate, no sabe cómo manejar los tipos JSON. Por lo tanto, debe usar un tipo de Hibernate personalizado, como el JsonBinaryType ofrece el proyecto Hibernate Types .
Primero, debe agregar la dependencia de Tipos de Hibernate:
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency> Después de establecer la propiedad Maven hibernate-types.version en la última versión, la dependencia se descargará de Maven Central.
No podrá usar la anotación Spring @Query ya que no puede configurar el tipo de hibernación explícitamente.
Por lo tanto, debe agregar una implementación personalizada del repositorio Spring Data JPA con el siguiente método:
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(); }¡Eso es todo!