Pregunta ¿Cómo insertar un registro actualizable con la columna JSON en PostgreSQL usando JOOQ?


Seguí la respuesta en ¿Es posible escribir un convertidor de tipo de datos para manejar las columnas JSON postgres?  para implementar el convertidor nodeObject.

Luego traté de usar un registro actualizable para insertar un registro, obtuve "org.jooq.exception.SQLDialectNotSupportedException: Type class org.postgresql.util.PGobject no se admite en el dialecto POSTGRES" excepción ".

¿Como puedo resolver esto?

Lo siguiente es mi código:

TableRecord r = create.newRecord(TABLE);
ObjectNode node = JsonNodeFactory.instance.objectNode();
r.setValue(TABLE.JSON_FIELD, node, new JsonObjectConverter());
r.store();

9
2017-11-20 16:31


origen


Respuestas:


Desde jOOQ 3.5, puede registrar sus propios enlaces de tipo de datos personalizados al generador de código como se documenta aquí:

http://www.jooq.org/doc/latest/manual/code-generation/custom-data-type-bindings

A diferencia de un Converter, un Binding dicta cómo se maneja su tipo de datos en el nivel JDBC dentro de jOOQ, sin que jOOQ sepa sobre su implementación. Es decir, no solo definirás cómo convertir entre <T> y <U> tipos (T = tipo de base de datos, U = tipo de usuario), pero también podrá definir cómo son esos tipos:

  • Prestado como SQL
  • Vinculado a estados preparados
  • Vinculado a SQLOutput
  • Registrado en CallableStatements como parámetros OUT
  • Obtenido de los ResultSets
  • Obtenido de SQLInput
  • Obtenido de CallableStatements como parámetros OUT

Un ejemplo Binding para usar con Jackson para producir JsonNode tipos se da aquí:

public class PostgresJSONJacksonJsonNodeBinding 
implements Binding<Object, JsonNode> {

    @Override
    public Converter<Object, JsonNode> converter() {
        return new PostgresJSONJacksonJsonNodeConverter();
    }

    @Override
    public void sql(BindingSQLContext<JsonNode> ctx) throws SQLException {

        // This ::json cast is explicitly needed by PostgreSQL:
        ctx.render().visit(DSL.val(ctx.convert(converter()).value())).sql("::json");
    }

    @Override
    public void register(BindingRegisterContext<JsonNode> ctx) throws SQLException {
        ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR);
    }

    @Override
    public void set(BindingSetStatementContext<JsonNode> ctx) throws SQLException {
        ctx.statement().setString(
            ctx.index(), 
            Objects.toString(ctx.convert(converter()).value()));
    }

    @Override
    public void get(BindingGetResultSetContext<JsonNode> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.resultSet().getString(ctx.index()));
    }

    @Override
    public void get(BindingGetStatementContext<JsonNode> ctx) throws SQLException {
        ctx.convert(converter()).value(ctx.statement().getString(ctx.index()));
    }

    // The below methods aren't needed in PostgreSQL:

    @Override
    public void set(BindingSetSQLOutputContext<JsonNode> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }

    @Override
    public void get(BindingGetSQLInputContext<JsonNode> ctx) throws SQLException {
        throw new SQLFeatureNotSupportedException();
    }
}

Y el Converter que se usa arriba se puede ver aquí:

public class PostgresJSONJacksonJsonNodeConverter 
implements Converter<Object, JsonNode> {
    @Override
    public JsonNode from(Object t) {
        try {
            return t == null 
              ? NullNode.instance 
              : new ObjectMapper().readTree(t + "");
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object to(JsonNode u) {
        try {
            return u == null || u.equals(NullNode.instance) 
              ? null 
              : new ObjectMapper().writeValueAsString(u);
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Class<Object> fromType() {
        return Object.class;
    }

    @Override
    public Class<JsonNode> toType() {
        return JsonNode.class;
    }
}

Ahora puede registrar el enlace anterior a través de la configuración del generador de código:

<customType>
    <name>com.example.PostgresJSONJacksonJsonNodeBinding</name>
    <type>com.fasterxml.jackson.databind.JsonNode</type>
    <binding>com.example.PostgresJSONJacksonJsonNodeBinding</binding>
</customType>

<forcedType>
    <name>com.example.PostgresJSONJacksonJsonNodeBinding</name>
    <expression>my_schema\.table\.json_field</expression>
</forcedType>

8
2017-11-26 10:34