Как мне обработать пустые поля, используя Mono <Connection>или DatabaseClient, предоставляемый R2dbc весной? - PullRequest
1 голос
/ 28 марта 2019

Я не знаю, как создать эффективный запрос в 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())...
   ...
}

OR

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). Если это явно не обсуждается, я все еще заинтересован в том, чтобы найти способ максимально эффективно реализовать это, учитывая то, с чем я работаю. Ценю любые отзывы.

1 Ответ

1 голос
/ 29 марта 2019

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

  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))

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...