简体   繁体   English

如何使用 Mono 处理可空字段<Connection>还是 R2dbc 在 Spring 中提供的 DatabaseClient?

[英]How do I handle nullable fields using either the Mono<Connection> or the DatabaseClient provided by R2dbc in Spring?

I am at a loss for how to contruct an efficient query in R2dbc (java) using spring-webflux (reactive).我不知道如何使用 spring-webflux (reactive) 在 R2dbc (java) 中构建有效的查询。 Using the DatabaseClient object provided by R2dbc (or alternatively, a Connection object), it seems that I am only able to call different variations of one of these two methods: bind(Object field, Object value) or bindNull(Object field, Class<?> type) .使用 R2dbc 提供的 DatabaseClient 对象(或一个 Connection 对象),似乎我只能调用这两种方法之一的不同变体: bind(Object field, Object value)bindNull(Object field, Class<?> type) If I have a schema, and a corresponding class in Java, with multiple nullable fields, how am I expected to handle this [somewhat] efficiently?如果我有一个架构和一个对应的 Java 类,有多个可为空的字段,我应该如何[有点]有效地处理这个问题?

Take for example:举个例子:

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()...
   ...
}

For my nullable fields I can replace .bind with .bindNull of course.对于我的可为空字段,我当然可以用 .bindNull 替换 .bind 。 The problem is that if I do call bind, the value cannot be null.问题是,如果我确实调用了绑定,则该值不能为空。 And if I call bindNull, the value must be null.如果我调用 bindNull,则该值必须为 null。 How would I be able to call one or the other based on whether my value is actually null?我如何能够根据我的值是否实际上为空来调用一个或另一个? I already know that I can just make a bunch of methods for each scenerio or call something along the lines of retryOnError.我已经知道我可以为每个场景创建一堆方法或沿着 retryOnError 调用一些方法。 But if I want to do a insertOrUpdate(List<Item> items) this would be wasting a ton of time/resources.但是如果我想做一个insertOrUpdate(List<Item> items)这将浪费大量的时间/资源。 Ideally I would like to do something analogous to if (field == null) ? bindNull("field", field.class) : bind("field", myObj.field)理想情况下,我想做一些类似于if (field == null) ? bindNull("field", field.class) : bind("field", myObj.field)事情if (field == null) ? bindNull("field", field.class) : bind("field", myObj.field) if (field == null) ? bindNull("field", field.class) : bind("field", myObj.field) somewhere somehow. if (field == null) ? bindNull("field", field.class) : bind("field", myObj.field)某处。 If that is clearly off the table, I am still interested in figuring out a way to implement this is as efficiently as possible given what I'm working with.如果这显然不在桌面上,我仍然有兴趣找出一种方法来尽可能有效地实现这一点,因为我正在使用它。 Appreciate any feedback.感谢任何反馈。

These are two questions:这是两个问题:

  1. How to bind potentially nullable values to a Statement / DatabaseClient in a fluent style?如何以流畅的方式将可能为空的值绑定到Statement / DatabaseClient
  2. How to let the database figure the rest out?如何让数据库解决剩下的问题?

R2DBC and Spring Data R2DBC make null handling explicit by requiring either binding a value to your Statement or binding a null . R2DBC和Spring数据R2DBC使null ,要求一个值绑定到你的处理明确Statement或绑定null There's no method of accepting a potentially nullable argument.没有方法可以接受可能为空的参数。 There are two reasons for that:有两个原因:

  1. You should deal with nullability to make obvious what happens there.您应该处理可空性以明确那里发生的事情。 That's a good habit to handle nullable values instead of making null handling implicit.这是一个很好的习惯来处理,而不是把空的值null处理隐。 The implicit nature of null is what causes the most bugs. null的隐含性质是导致最多错误的原因。
  2. Being explicit is required by databases.数据库要求显式。 Parametrized statements with placeholders consist on the execution side of two chunks: The SQL statement itself and parameters bindings (descriptors).带有占位符的参数化语句包含在两个块的执行端:SQL 语句本身和参数绑定(描述符)。 A parameter descriptor requires an association to a placeholder, type information ( VARCHAR , BIT , INT , …) and the actual value.参数描述符需要与占位符、类型信息( VARCHARBITINT等)和实际值的关联。 With calling bind(…) with a value, a driver can derive the type information.通过使用值调用bind(…) ,驱动程序可以派生类型信息。 When binding a null value, the driver requires an additional type of information.绑定null值时,驱动程序需要其他类型的信息。 Otherwise, we cannot execute the query.否则,我们无法执行查询。

That being said:话虽如此:

  1. There's no API like bindPotentiallyNull("auditId", entity.getTx().getId(), Integer.class)没有像bindPotentiallyNull("auditId", entity.getTx().getId(), Integer.class)这样的 API
  2. You cannot do anything within the SQL query because binding parameter information is supplied by auxiliary methods.您不能在 SQL 查询中执行任何操作,因为绑定参数信息是由辅助方法提供的。

We face a similar issue when talking about stored procedures, because stored procedures require additional details about in/out/in-out parameters.在谈论存储过程时,我们面临类似的问题,因为存储过程需要有关输入/输出/输入输出参数的其他详细信息。 We discussed potential wrapper types like我们讨论了潜在的包装器类型,例如

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

so these could be used as wrappers in所以这些可以用作包装器

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

Further details:更多细节:

Either setting a value or null can be done using the Parameter class as shown below:可以使用Parameter类设置值或空值,如下所示:

import org.springframework.r2dbc.core.Parameter;

// rest of the code

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

Earlier, it was SettableValue.fromOrEmpty , which is not deprecated.早些时候,它是SettableValue.fromOrEmpty ,它没有被弃用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM