如何在Spring Data JDBC中读写PostgreSQL的jsonb类型?

6

我正在尝试在spring-data-jdbc和postgres驱动程序(kotlin)中使用以下内容:

data class MyEntity(
  val id: UUID,
  val content: String
)

使用字符串时会出现以下错误:
org.postgresql.util.PSQLException: ERROR: column "content" is of type jsonb but expression is of type character varying
  Hint: You will need to rewrite or cast the expression.
  Position: 31

我不确定如何使用将字符串转换为jsonb的转换器。


这个回答解决了你的问题吗?关于Spring Data JDBC + Hikari + Postgres JSONB的问题 - Jens Schauder
1个回答

9

借助这个的帮助,我实现了以下解决方案:

  1. 引入一个自己的类(POJO/kotlin数据类),用于保存json文档的结构(称为 MyContent
  2. 实现转换器的编写和阅读,将POJO转换为字符串(例如使用jackson
  3. 使用org.postgresql.util.PGobject指定postgres列类型

详细信息(仅伪代码):

import org.springframework.core.convert.converter.Converter
import org.springframework.data.convert.ReadingConverter
import org.springframework.data.convert.WritingConverter
import com.fasterxml.jackson.databind.ObjectMapper
import org.postgresql.util.PGobject

@Table("my_entity")
data class MyEntity(
  @Id val id: UUID,
  val content: MyContent
) {

  @WritingConverter
  class EntityWritingConverter(
      private val objectMapper: ObjectMapper
  ) : Converter<MyContent, PGobject> {
      override fun convert(source: MyContent): PGobject? {
          val jsonObject = PGobject()
          jsonObject.type = "json"
          jsonObject.value = objectMapper.writeValueAsString(source)
          return jsonObject
      }
  }

  @ReadingConverter
  class EntityReadingConverter(
      private val objectMapper: ObjectMapper
  ) : Converter<PGobject, MyContent> {
      override fun convert(pgObject: PGobject): MyContent {
          val source = pgObject.value
          return objectMapper.readValue<MyContent>(source)
      }
  }
}

不要忘记将这两个转换器添加到 spring-data-jdbc 的配置中(参见 JdbcCustomConversions)。

这适用于对应的 Postgres 表:

create table if not exists my_entity
(
    id uuid not null primary key,
    content jsonb
);


在我的情况下,这个解决方案不起作用。Spring将自定义POJO视为相关实体,并使用JOIN my_content ...进行查询。我按照您的建议做了一切,按照Spring文档注册了自定义转换器,但仍然无法正常工作。也许您有任何想法,可能出了什么问题? - RomanMitasov
2
记录一下。重要的是要同时拥有@ReadingConverter@WritingConverter,以使spring-data-jbdc将MyContent视为简单类型。否则,sping-data会生成带有“JOIN my_content”部分的SQL。更重要的是,实际上只有@WritingConverter起作用,因为在spring-data内部它用于注册自定义简单类型。 - RomanMitasov
@RomanMitasov,你是如何让spring-data-jdbc将实体视为简单类型的? - Kirill
@Kirill 为实体类型注册 @WritingConverter 会使 Spring Data JDBC 将该类型视为简单类型。我在之前的评论中提到过这一点。 - RomanMitasov
谢谢,@RomanMitasov,你是正确的。我的问题最终证明是不同的:一旦你尝试在自动生成的存储库方法中使用存储为JSONB的对象的字段,spring-data-jdbc似乎拒绝再将此对象视为简单类型。否则,你上面写的代码很好用。 我无法“修复”这个问题,所以我转而使用自定义查询。 - Kirill

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