Как мне обработать пустые поля, используя 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 ответа
Это два вопроса:
- Как связать потенциально обнуляемые значения с
Statement
/DatabaseClient
в свободном стиле? - Как дать базе данных понять остальное?
R2DBC и Spring Data R2DBC делают null
обработка явно, требуя либо привязки значения к вашему Statement
или связывание null
, Нет способа принять потенциально обнуляемый аргумент. Для этого есть две причины:
- Вы должны иметь дело с обнуляемостью, чтобы понять, что там происходит. Это хорошая привычка обрабатывать обнуляемые значения вместо
null
обработка неявная. Неявная природаnull
это то, что вызывает большинство ошибок. - Быть явным требуется для баз данных. Параметризованные операторы с заполнителями состоят на стороне выполнения двух блоков: самого оператора SQL и привязок параметров (дескрипторов). Дескриптор параметра требует ассоциации с заполнителем, тип информации (
VARCHAR
,BIT
,INT
,…) И фактическая стоимость. С вызовомbind(…)
со значением драйвер может получить информацию о типе. При связыванииnull
Значение, драйвер требует дополнительного типа информации. В противном случае мы не сможем выполнить запрос.
Что, как говорится:
- Там нет API, как
bindPotentiallyNull("auditId", entity.getTx().getId(), Integer.class)
- Вы не можете ничего сделать в запросе 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
, который не устарел.