【问题标题】:jOOQ - How to update a jsonb column with an array in a Postgres table to avoid SQLDialectNotSupportedExceptionjOOQ - 如何使用 Postgres 表中的数组更新 jsonb 列以避免 SQLDialectNotSupportedException
【发布时间】:2018-03-28 05:53:08
【问题描述】:

我有一个带有 jsonb 列的 PostgreSQL 表,其中包含一个字符串数组,这些字符串是标记值,例如:["tag1", "tag2", "tag3"]。我有一个自定义绑定,可以将 JSON 与 jackson JsonNode 相互转换。

自定义绑定在这里定义:https://gist.github.com/HelgeG/0c0b14228f75e91b7542bd6979a05b49

使用基本查找读取记录,然后按如下方式提取 JSON 列:

VRelease release = releaseModel.find(id);
JsonNode tagNode = release.getTags();

节点转换为List<String>

  List<String> tagList = objectMapper.readValue(
      tagNode.toString(),
      objectMapper.getTypeFactory().constructCollectionType(
          List.class, String.class));

然后我将一个字符串添加到列表中并将列表转换回 JSON 格式的字符串

  tagList.add(tag);
  String jsonString = objectMapper.writeValueAsString(tagList);

然后我将 JSON 格式的字符串转换为 JsonNode,并尝试将其写回数据库:

  releaseModel.writeTags(id, objectMapper.readValue(jsonString, JsonNode.class));

writeTags 方法只执行以下操作:

  public int writeTags(Integer id, JsonNode tagList) {
    return ctx.update(TABLE).set(field(TAG_FIELD_NAME), tagList).where(PRIMARY_KEY.eq(id))
        .execute();
  }

但是,在执行此查询时,我收到以下异常:

org.jooq.exception.SQLDialectNotSupportedException: Type class com.fasterxml.jackson.databind.node.ArrayNode is not supported in dialect POSTGRES

在调试器中检查 JsonNode 对象,它的值是:

我已经为此苦苦挣扎了很长一段时间,如果 jOOQers 有比我更有经验的关于如何成功将 JSON 数组写入数据库的任何指示,我将不胜感激。

这适用于 jOOQ v3.9.5 和 PostgreSQL 9.6.5。

【问题讨论】:

  • 我很抱歉造成混乱。我要问的是您如何将List&lt;String&gt; 设置为该字段。我的意思是你将List&lt;String&gt; 传递给set() 方法,但是你是如何指定TAG_FIELD_NAMEDataType 的?是DataType&lt;List&lt;String&gt;&gt; 吗?你是如何配置绑定的?您链接的绑定是Binding&lt;Object, JsonNode&gt;,但从您发布的代码中,应该有一个Binding&lt;Object, List&lt;String&gt;&gt;...
  • @LukasEder 我看到了混淆的来源,因为我在不同的上下文中重用了相同的变量名(一次用于列表,另一次用于 JsonNode)而没有正确描述它。当我调用 writeTags 方法时,我传递的是一个 JsonNode 对象,而不是一个列表。上面我已经在调试器中包含了 JsonNode 值的屏幕截图。抱歉,不清楚,感谢您的帮助和耐心。

标签: java json postgresql jooq


【解决方案1】:

我假设 TAG_FIELD_NAME 只是一个简单的 String 描述您的列名。在那种情况下,解释很简单。 jOOQ 对JsonNode 类型的自定义Binding 一无所知,更不用说List&lt;ArrayNode&gt;

您的代码编译是因为您使用的是DSL.field(String),它返回Field&lt;Object&gt;。但是这样的字段只能与 jOOQ 和 JDBC 驱动程序都知道如何处理的“普通”JDBC 类型一起使用。为了真正绑定数据类型绑定到你的字段,你必须将它提供给jOOQ。改为这样写:

DataType<List<ArrayNode>> ARRAY_NODE_LIST = SQLDataType.OTHER.asConvertedDataType(
    new ArrayNodeListBinding());

然后按如下方式使用:

ctx.update(TABLE)
   .set(field(TAG_FIELD_NAME, ARRAY_NODE_LIST), tagList)
   // your new data type here ^^^^^^^^^^^^^^^
   .where(PRIMARY_KEY.eq(id))
   .execute();

现在您只需编写该绑定。您发布的绑定在这里不起作用,因为它绑定JsonNode,而不是List&lt;ArrayNode&gt;

【讨论】:

  • 作为处理具有可变内容的 JSON 字符串的一般形式,我是否可以使用在常规 String 和 PostgreSQL JSONB 列类型之间转换的绑定并以与上述相同的方式使用它?跨度>
  • 当然,它会比上面没有那么具体,并且只接受可变 JSON 内容的通用超类型(而不是 List&lt;ArrayNode&gt;),但这可能更适合大多数情况。 .
猜你喜欢
  • 2019-03-04
  • 2020-05-06
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
相关资源
最近更新 更多