JOOq:广义更新 table
JOOq: update for generalized table
我想用 JOOq 创建一个 generalized 方法,它使用来自 JSON 对象的值更新 table(由字符串指定)。在此示例中,我没有包括 tables/fields 的任何验证。
public void updateTable(String table, JsonObject data) {
Table<?> table = PUBLIC.getTable(table);
UpdateSetFirstStep<?> update = DSL.using(fooConfig).update(table);
// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
String fieldName = entry.getKey();
Field<?> field = table.field(fieldName);
Object value = entry.getValue();
// error: no suitable method found for set(Field<CAP#1>,CAP#2)
update.set(field, field.getType().cast(value));
}
}
但是我得到一个编译时错误:no suitable method found for set(Field<CAP#1>,CAP#2)
。
我认为问题在于编译器不知道字段的类型和值的类型将相同(因此 CAP#1 和 CAP#2)。
有什么办法可以做到吗?
I think the problem is that the compiler doesn't know that the type of the field and the type of the value will be the same (hence CAP#1 and CAP#2).
这正是问题所在。同一通配符类型的两种不同用途产生了两种不同的新捕获类型。
解决方案是引入一个小方法,其中通配符类型使用一次并绑定到一个类型参数。当它绑定到一个类型参数时,编译器会识别不同的用法指的是同一种类型。
像这样:
public void updateTable(String name, JsonObject data) {
Table<?> table = PUBLIC.getTable(name);
UpdateSetFirstStep<?> update = DSL.using(fooConfig).update(table);
// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
String fieldName = entry.getKey();
Field<?> field = table.field(fieldName);
Object value = entry.getValue();
// Here the wildcard type is bound to the
// type variable of the updateField method
updateField(update, field, value);
}
}
public <T> void updateField(UpdateSetStep<?> update, Field<T> field, Object value) {
// When the wildcard is bound to T it can be used
// multiple times without a problem
update.set(field, field.getType().cast(value));
}
另一个解决方案
...是将字段类型转换为某种具体类型:
@SuppressWarnings("unchecked")
Field<Object> field = (Field<Object>) table.field(fieldName);
update.set(field, field.getType().cast(entry.getValue()));
输入的代码更少,在这个简单的示例中它工作正常。但它的类型安全性也较低,因此在更复杂的代码中,引入带有类型参数的方法可能更好。
例如,以下类型检查但可能在运行时崩溃:
update.set(field, entry);
第三个有趣的解决方案
...将能够为 Field
:
声明局部类型变量
<T> Field<T> field = table.field(fieldName);
但这当然是不合法的Java,类型变量只能作为参数引入类和方法,不能引入局部变量。
第四种解决方案,使用 lambdas
...就是定义一个util方法,传递一个lambda对象给它。它的工作方式与第一个解决方案相同,但您不必为每件事都创建自定义方法。
// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
String fieldName = entry.getKey();
Field<?> field = table.field(fieldName);
Object value = entry.getValue();
captureType(field, f -> update.set(f, f.getType().cast(value)));
}
public static <T> void captureType(T o, Consumer<T> c) {
c.accept(o);
}
它的一个变体是使用一些现有的方法来获得相同的结果:
Optional.of(field).ifPresent(f -> update.set(f, f.getType().cast(value)));
最简单的解决方案是为此使用 UpdateSetStep.set(Map<? extends Field<?>, ?>)
方法。它应用相当宽松的类型安全为您进行数据类型转换(如果可能):
public void updateTable(String table, JsonObject data) {
Table<?> table = PUBLIC.getTable(table);
DSL.using(fooConfig)
.update(table)
.set(data.entrySet()
.stream()
.map(e -> new SimpleImmutableEntry(table.field(e.getKey()), e.getValue()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue)))
.where(...) // Don't forget this! ;-)
.execute();
}
通过上面的解决方案我想到了这种捷径
public void update(final String db, final String tbl, final Map<Field<?>, ?> data, final Condition condition) {
dslContext.update(DSL.table(db + "." + tbl)).set(data).where(condition).execute();
}
在 Quarkus @Inject DSLContext dslContext
在你的 class
我想用 JOOq 创建一个 generalized 方法,它使用来自 JSON 对象的值更新 table(由字符串指定)。在此示例中,我没有包括 tables/fields 的任何验证。
public void updateTable(String table, JsonObject data) {
Table<?> table = PUBLIC.getTable(table);
UpdateSetFirstStep<?> update = DSL.using(fooConfig).update(table);
// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
String fieldName = entry.getKey();
Field<?> field = table.field(fieldName);
Object value = entry.getValue();
// error: no suitable method found for set(Field<CAP#1>,CAP#2)
update.set(field, field.getType().cast(value));
}
}
但是我得到一个编译时错误:no suitable method found for set(Field<CAP#1>,CAP#2)
。
我认为问题在于编译器不知道字段的类型和值的类型将相同(因此 CAP#1 和 CAP#2)。
有什么办法可以做到吗?
I think the problem is that the compiler doesn't know that the type of the field and the type of the value will be the same (hence CAP#1 and CAP#2).
这正是问题所在。同一通配符类型的两种不同用途产生了两种不同的新捕获类型。
解决方案是引入一个小方法,其中通配符类型使用一次并绑定到一个类型参数。当它绑定到一个类型参数时,编译器会识别不同的用法指的是同一种类型。
像这样:
public void updateTable(String name, JsonObject data) {
Table<?> table = PUBLIC.getTable(name);
UpdateSetFirstStep<?> update = DSL.using(fooConfig).update(table);
// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
String fieldName = entry.getKey();
Field<?> field = table.field(fieldName);
Object value = entry.getValue();
// Here the wildcard type is bound to the
// type variable of the updateField method
updateField(update, field, value);
}
}
public <T> void updateField(UpdateSetStep<?> update, Field<T> field, Object value) {
// When the wildcard is bound to T it can be used
// multiple times without a problem
update.set(field, field.getType().cast(value));
}
另一个解决方案
...是将字段类型转换为某种具体类型:
@SuppressWarnings("unchecked")
Field<Object> field = (Field<Object>) table.field(fieldName);
update.set(field, field.getType().cast(entry.getValue()));
输入的代码更少,在这个简单的示例中它工作正常。但它的类型安全性也较低,因此在更复杂的代码中,引入带有类型参数的方法可能更好。
例如,以下类型检查但可能在运行时崩溃:
update.set(field, entry);
第三个有趣的解决方案
...将能够为 Field
:
<T> Field<T> field = table.field(fieldName);
但这当然是不合法的Java,类型变量只能作为参数引入类和方法,不能引入局部变量。
第四种解决方案,使用 lambdas
...就是定义一个util方法,传递一个lambda对象给它。它的工作方式与第一个解决方案相同,但您不必为每件事都创建自定义方法。
// Loop through JSON {field1: value1, field2: value2, ...}
for (Map.Entry<String, Object> entry : data) {
String fieldName = entry.getKey();
Field<?> field = table.field(fieldName);
Object value = entry.getValue();
captureType(field, f -> update.set(f, f.getType().cast(value)));
}
public static <T> void captureType(T o, Consumer<T> c) {
c.accept(o);
}
它的一个变体是使用一些现有的方法来获得相同的结果:
Optional.of(field).ifPresent(f -> update.set(f, f.getType().cast(value)));
最简单的解决方案是为此使用 UpdateSetStep.set(Map<? extends Field<?>, ?>)
方法。它应用相当宽松的类型安全为您进行数据类型转换(如果可能):
public void updateTable(String table, JsonObject data) {
Table<?> table = PUBLIC.getTable(table);
DSL.using(fooConfig)
.update(table)
.set(data.entrySet()
.stream()
.map(e -> new SimpleImmutableEntry(table.field(e.getKey()), e.getValue()))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue)))
.where(...) // Don't forget this! ;-)
.execute();
}
通过上面的解决方案我想到了这种捷径
public void update(final String db, final String tbl, final Map<Field<?>, ?> data, final Condition condition) {
dslContext.update(DSL.table(db + "." + tbl)).set(data).where(condition).execute();
}
在 Quarkus @Inject DSLContext dslContext
在你的 class