Jooq - обновление поля до NULL делает его нулевым, а не NULL

Это был мой запрос, который раньше работал в jooq 3.11.

Я обновляю поле JSON, однако в моей модели оно отображается на String с помощью привязки JsonBinding, которую я опубликую ниже.

        dsl.update(TASK)
            .set(TASK.JSON_SOLUTION, (String) null).            
        .where(TASK.TENANT.eq(getCurrentTenant()))
        .and(TASK.TASK_TEMPLATE_ID.in(taskTemplateIds));execute()

Теперь это больше не работает после обновления до jooq 3.13.2. Мне также пришлось изменить свой диалект sql на mysql, хотя я работаю с базой данных mysql 5_7, это может быть проблемой?

Я тоже пробовал это, и он все тот же

        dsl.update(TASK)
            .setNull(TASK.JSON_SOLUTION).            
         .where(TASK.TENANT.eq(getCurrentTenant()))
        .and(TASK.TASK_TEMPLATE_ID.in(taskTemplateIds));execute()

JsonBinding.class

public class JsonBinding implements Binding<JSON, String> {

  @Override
  public Converter<JSON, String> converter() {
    return new JsonConverter();
  }

  @Override
  public void sql(BindingSQLContext<String> bindingSQLContext) {
    if (bindingSQLContext.render().paramType() == ParamType.INLINED) {
      bindingSQLContext
          .render()
          .visit(DSL.inline(bindingSQLContext.convert(converter()).value()))
          .sql("::json");
    } else {
      bindingSQLContext.render().sql("?");
    }
  }

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

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

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

  @Override
  public void get(BindingGetResultSetContext<String> bindingGetResultSetContext)
      throws SQLException {
    bindingGetResultSetContext
        .convert(converter())
        .value(
            JSON.valueOf(
                bindingGetResultSetContext
                    .resultSet()
                    .getString(bindingGetResultSetContext.index())));
  }

  @Override
  public void get(BindingGetStatementContext<String> bindingGetStatementContext)
      throws SQLException {
    bindingGetStatementContext
        .convert(converter())
        .value(
            JSON.valueOf(
                bindingGetStatementContext
                    .statement()
                    .getString(bindingGetStatementContext.index())));
  }

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

JsonConverter.class

public class JsonConverter implements Converter<JSON, String> {

  @Override
  public String from(JSON object) {
    return object != null ? object.toString() : null;
  }

  @Override
  public JSON to(String string) {
    return JSON.valueOf(string);
  }

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

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

Вот запрос, который jooq запускает с .setNull ()

update `tasks_service`.`task` set `tasks_service`.`task`.`json_solution` = 'null'::json where (`tasks_service`.`task`.`tenant` = 'skynet' and `tasks_service`.`task`.`task_template_id` in ('55', '33'))

Перед обновлением на jooq 3.11 запрос выглядит следующим образом

update `tasks_service`.`task` set `tasks_service`.`task`.`json_solution` = null::json where (`tasks_service`.`task`.`tenant` = 'skynet' and `tasks_service`.`task`.`task_template_id` in ('55', '33'))

Итак, до его установки 'json_solution' = null и после обновления, похоже, установлено 'json_solution' = 'null'

Не совсем уверен, почему это происходит?

Изменить: Итак, из того, что я могу сказать, это похоже на обновление в JOOQ, а не на sql-диалекте. Используя Jooq 3.11.5 с mysql и mysql

update `tasks_service`.`task` set `tasks_service`.`task`.`json_solution` = 'null'::json where (`tasks_service`.`task`.`tenant` = 'skynet' and `tasks_service`.`task`.`task_template_id` in ('55', '33'))
7 в качестве диалектов, запрос строится как set 'json_solution' = null, если я обновляю JOOQ до 3.13.2, его set 'json_solution' = 'null'

Эта причуда также, кажется, происходит только в поле JSON, я попытался установить другое поле строки varchar String равным null в той же таблице, и я получил правильный набор field_name '= null

Проблема может быть в моем JsonBinding / JsonConverter? Мне пришлось немного изменить его, чтобы работать с новым объектом JSON в JOOQ, поскольку ранее JOOQ отображал JSON как объект


person HelloWhatsMyName1234    schedule 12.08.2020    source источник
comment
как выглядит выполненный SQL?   -  person Simon Martinelli    schedule 12.08.2020
comment
Обновлен OP с запросом   -  person HelloWhatsMyName1234    schedule 12.08.2020


Ответы (1)


JSON.valueOf(null) vs (JSON) null

Ответ находится в документации Javadoc org.jooq.JSON. :

Значение CAST(NULL AS JSON) представлено ссылкой null типа JSON, а не data() == null. Это соответствует общему способу jOOQ возврата NULL из методов Result и Record.

Итак, ошибка в JsonConverter использовании _ 12_. Напишите вместо этого:

  public JSON to(String string) {
    return string == null ? null : JSON.valueOf(string);
  }

Или просто используйте _ 14_, который обрабатывает преобразование NULL в NULL за вас:

Converter<JSON, String> converter = Converter.ofNullable(
  JSON.class,
  String.class,
  JSON::data,
  JSON::json
);

Боковое примечание об использовании Binding

Вам больше не нужна привязка, поскольку тип JSON изначально поддерживается jOOQ. Если вы хотите преобразовать JSON в String, вашего Converter будет достаточно.

person Lukas Eder    schedule 13.08.2020
comment
Я сделал это первое изменение и получил обновление запроса _1 _._ 2_ set _3 _._ 4 _._ 5_ = null :: json, где (_6 _._ 7 _._ 8_ = 'skynet' и _9 _._ 10 _._ 11_ in ('55', '33 ')) 2020-08-13 08: 57: 44.403 DEBUG 10058 --- [main] org.jooq.tools.LoggerListener: Затронутые строки: 2 - person HelloWhatsMyName1234; 13.08.2020
comment
Однако он по-прежнему установлен как null в БД, а не как NULL. - person HelloWhatsMyName1234; 13.08.2020
comment
Я могу скопировать и вставить запрос в свою БД, и он работает так, как задумано, однако jooq, похоже, устанавливает его как null - person HelloWhatsMyName1234; 13.08.2020
comment
@ HelloWhatsMyName1234: разница, которую вы наблюдаете, связана с тем, что вы копируете вставку вывода журнала отладки, который содержит встроенные значения привязки (где вы явно приводите к json), тогда как jOOQ выполняет подготовленный оператор. Вы все еще используете пользовательскую привязку? Я не проверял его полностью, потому что предполагал, что вы его уроните. Например, я подозреваю, что это неправильно: sql("?"). Вам нужно будет указать значение привязки как ?::json - person Lukas Eder; 13.08.2020
comment
Так что у меня есть :: json чуть выше этого в привязке. Я установил обе части оператора if / else как? :: json, и мне кажется, что я получаю исключения синтаксиса Sql. Как мне перестать использовать привязку и сохранить то же неявное поведение, которое я использую сейчас? Прямо сейчас в моем помпе для генератора у меня есть следующее - person HelloWhatsMyName1234; 13.08.2020
comment
‹CedTypes› ‹forcedType› ‹userType› Строка ‹/userType› ‹binding› api.task.repo.json.JsonBinding ‹/binding› ‹expression›. * JSON. * ‹/Expression› ‹types›. * JSON. * ‹/Types› ‹/forcedType› ‹/forceTypes› - person HelloWhatsMyName1234; 13.08.2020
comment
Я знаю, что мог бы просто использовать объект JOOQ.JSON, но я все еще хочу привязать его к строке неявно, как это происходит сейчас, изменение объекта на JOOQ.JSON потребовало бы множества изменений в кодовой базе, которых я пытаюсь избежать. - person HelloWhatsMyName1234; 13.08.2020
comment
просто замените спецификацию <binding/> на <converter>api.task.repo.json.JsonConverter</converter> или какой-либо другой пакет, который есть. Мне пришлось бы попытаться воспроизвести проблемы с привязкой, но, начиная с того момента, когда поддерживались типы JSON, было маловероятно, что кто-то по-прежнему будет использовать привязку для типов JSON, если вам действительно не нужно привязать тип вручную с помощью каких-то эзотерических вызовов JDBC API. - person Lukas Eder; 13.08.2020