PostgreSQL throws "column is of type jsonb but expression is of type bytea" with JPA and Hibernate

Ari*_*ain 8 java postgresql hibernate jpa jsonb

This is my entity class that is mapped to a table in postgres (9.4) I am trying to store metadata as jsonb type in the database

@Entity
@Table(name = “room_categories”)
@TypeDef(name = “jsonb”, typeClass = JsonBinaryType.class)
public class RoomCategory extends AbstractEntity implements Serializable {
    private String name;
    private String code;
    @Type(type = "jsonb")
    @Column(columnDefinition = "json")
    private Metadata metadata;

}
Run Code Online (Sandbox Code Playgroud)

This is the metadata class:

public class Metadata implements Serializable {
    private String field1;
    private String field2;

}
Run Code Online (Sandbox Code Playgroud)

I have used following migration file to add jsonb column:

databaseChangeLog:
– changeSet:
id: addColumn_metadata-room_categories
author: arihant
changes:
– addColumn:
schemaName: public
tableName: room_categories
columns:
– column:
name: metadata
type: jsonb
Run Code Online (Sandbox Code Playgroud)

I am getting this error while creating the record in postgres: ERROR: column “metadata” is of type jsonb but expression is of type bytea Hint: You will need to rewrite or cast the expression.

This is the request body i am trying to persist in db:

  {
    “name”: “Test102”,
    “code”: “Code102”,
    “metadata”: {
    “field1”: “field11”,
    “field2”: “field12”
    }
    }
Run Code Online (Sandbox Code Playgroud)

Please help how to convert bytea type to jsonb in java spring boot app

小智 7

如果使用JpaRespository保存接口方法,可以在issue属性上方添加cast方法

@ColumnTransformer(write = "?::jsonb")
private Metadata metadata;
Run Code Online (Sandbox Code Playgroud)


Ali*_*our 5

只需通过 ObjectMapper 将您的对象转换为 json 字符串,然后使用 (::jsonb) 作为强制转换为 jsonb 类型:

INSERT INTO room_categories (name, code, metadata)
    VALUES (?, ?, ? ::jsonb ); 
Run Code Online (Sandbox Code Playgroud)

(您将需要使用本机查询来查询存储为 jsonb 的数据)


Vla*_*cea 4

错误原因

\n

你可以得到这个 PostgreSQL:

\n
\n

错误:列 \xe2\x80\x9cmetadata\xe2\x80\x9d 的类型为 jsonb,但表达式的类型为 bytea 提示:您将需要重写或转换表达式。

\n
\n

如果您正在执行本机 SQL DML 语句。

\n

原生 SQL DML 语句

\n

例如,假设您想做这样的事情:

\n
int updateCount = entityManager.createNativeQuery("""\n    UPDATE\n        room_categories\n    SET\n        metadata = :metadata\n    WHERE\n        code = :code AND\n        metadata ->> 'field1' is null            \n    """)\n.setParameter("code ", "123-ABC")\n.setParameter(\n    "metadata",\n    new Metadata()\n        .setField1("ABC")\n        .setField2("123")\n)\n.executeUpdate();\n
Run Code Online (Sandbox Code Playgroud)\n

bytea类型代表字节数组,并且由于该Metadata类型实现了该接口,因此当没有其他类型更合适时,SerializableHibernate 会回退到使用。SerializableType

\n

但是,由于您无法将字节数组绑定到jsonb列,因此 PostgreSQL 会抛出上述错误。

\n

修复

\n

要修复它,我们必须JsonBinaryType使用 Hibernate 特定的setParameter Query方法显式设置:

\n
int updateCount = entityManager.createNativeQuery("""\n    UPDATE\n        room_categories\n    SET\n        metadata = :metadata\n    WHERE\n        code = :code AND\n        metadata ->> 'field1' is null            \n    """)\n.setParameter("code ", "123-ABC")\n.unwrap(org.hibernate.query.Query.class)\n.setParameter(\n    "metadata",\n    new Metadata()\n        .setField1("ABC")\n        .setField2("123"),\n    JsonBinaryType.INSTANCE\n)\n.executeUpdate();\n
Run Code Online (Sandbox Code Playgroud)\n

首先,我们必须将unwrapJPA连接Query到 Hibernateorg.hibernate.query.Query并调用setParameter采用 Hibernate Type 实例的方法。

\n

现在,Hibernate 将知道该metadata参数需要由 处理JsonBinaryType,而不是由 处理SerializableType

\n