Как мне обработать пустые поля, используя Mono<Connection> или DatabaseClient, предоставляемый R2dbc в Spring?

Я в растерянности из-за того, как создать эффективный запрос в R2dbc (java), используя spring-webflux (реактивный). Используя объект DatabaseClient, предоставляемый R2dbc (или, альтернативно, объектом Connection), кажется, что я могу вызвать только разные варианты одного из этих двух методов: bind(Object field, Object value) или же bindNull(Object field, Class<?> type), Если у меня есть схема и соответствующий класс в Java с несколькими обнуляемыми полями, как мне ожидать, что я справлюсь с этим несколько?

Взять, к примеру:

public Flux<Item> saveOrUpdate(Item entity) {

   Mono<Connection> connection = this.connection; 

   Flux<? extends Result> itemFlux = connection
       .doOnError(e -> e.printStackTrace())
           .flatMapMany(connect  ->  connect.createStatement(INSERT_OR_UPDATE_ITEM)
                .bind("itemId", entity.getItemId()).returnGeneratedValues("itemid")
                .bind("auditId", entity.getTx().getId())
                .bind("itemNum", entity.getItemNum())
                .bind("itemCat", entity.getItemCat()) //nullable
                 // How would I know when to use this?
                .bindNull("sourcedQty", Integer.class) //nullable
                .bind("makeQty", entity.getMakeQty())
                .bind("nameShown", entity.getNameShown()) //nullable
                .bind("price", entity.price())
                .bind("dateCreated", entity.getDateCreated()) //nullable
                .add()
                .execute())...
   ...
}

ИЛИ ЖЕ

public Mono<Item> saveOrUpdate(Item entity){

   Mono<Item> itemMono = databaseClient.execute.sql(INSERT_OR_UPDATE_ITEM)
      .bind("itemId", entity.getItemId()).returnGeneratedValues("itemid")
                .bind("auditId", entity.getTx().getId())
                .bind("itemNum", entity.getItemNum())
                .bind("itemCat", entity.getItemCat())
                .bind("sourcedQty", entity.getSourcedQty()) 
                .bind("makeQty", entity.getMakeQty())
                .bind("nameShown", entity.getNameShown())
                .bind("price", entity.price())
                .bind("dateCreated", entity.getDateCreated())
                .as(Item.class)
                .fetch()
                .one()...
   ...
}

Для моих пустых полей я могу заменить.bind на.bindNull, конечно. Проблема в том, что если я вызову связывание, значение не может быть нулевым. И если я вызываю bindNull, значение должно быть нулевым. Как я мог бы вызвать один или другой в зависимости от того, действительно ли мое значение равно нулю? Я уже знаю, что я могу просто сделать несколько методов для каждого сценария или вызвать что-то вроде retryOnError. Но если я хочу сделать insertOrUpdate(List<Item> items) это будет тратить кучу времени / ресурсов. В идеале я хотел бы сделать что-то аналогичное if (field == null) ? bindNull("field", field.class) : bind("field", myObj.field) где-то как-то Если это явно не обсуждается, я все еще заинтересован в том, чтобы найти способ максимально эффективно реализовать это, учитывая то, с чем я работаю. Ценю любые отзывы.

2 ответа

Решение

Это два вопроса:

  1. Как связать потенциально обнуляемые значения с Statement/DatabaseClient в свободном стиле?
  2. Как дать базе данных понять остальное?

R2DBC и Spring Data R2DBC делают null обработка явно, требуя либо привязки значения к вашему Statement или связывание null, Нет способа принять потенциально обнуляемый аргумент. Для этого есть две причины:

  1. Вы должны иметь дело с обнуляемостью, чтобы понять, что там происходит. Это хорошая привычка обрабатывать обнуляемые значения вместо null обработка неявная. Неявная природа null это то, что вызывает большинство ошибок.
  2. Быть явным требуется для баз данных. Параметризованные операторы с заполнителями состоят на стороне выполнения двух блоков: самого оператора SQL и привязок параметров (дескрипторов). Дескриптор параметра требует ассоциации с заполнителем, тип информации (VARCHAR, BIT, INT,…) И фактическая стоимость. С вызовом bind(…) со значением драйвер может получить информацию о типе. При связывании null Значение, драйвер требует дополнительного типа информации. В противном случае мы не сможем выполнить запрос.

Что, как говорится:

  1. Там нет API, как bindPotentiallyNull("auditId", entity.getTx().getId(), Integer.class)
  2. Вы не можете ничего сделать в запросе SQL, потому что информация о параметрах привязки предоставляется вспомогательными методами.

Мы сталкиваемся с аналогичной проблемой, когда говорим о хранимых процедурах, потому что хранимые процедуры требуют дополнительной информации о параметрах in / out / in-out. Мы обсуждали потенциальные типы оберток, такие как

Parameters.in(@Nullable T value, Class<? super T> valueType)

так что они могут быть использованы в качестве оберток в

bind("auditId", Parameters.in(entity.getTx().getId(), Integer.class))

Более подробная информация:

Либо установка значения, либо null может быть выполнена с помощью Parameterкласс, как показано ниже:

      import org.springframework.r2dbc.core.Parameter;

// rest of the code

.bind("customerId", Parameter.fromOrEmpty(o.getCustomerId(), UUID.class))

Раньше это было SettableValue.fromOrEmpty, который не устарел.

Другие вопросы по тегам