Table 重塑
Table re-shaping
我正在使用设计非常糟糕的数据库,我需要在编写查询之前重新调整表格。
以下是我的常见问题:
- 时间戳已分为两列(一列用于日期,另一列用于时间)。
- 一些字符串列也被拆分成多个列。
- 大多数字符串都有固定长度和空白填充,所以我需要 trim 它们。
我首先考虑调整 Jooq 生成器的输出。但是查看 createField(...)
方法,它将字段附加到包私有的 fields0()
。这使得 SELECT *
查询所有(且仅)"raw" 个字段,而不是重新整形的字段。
静态(即class/member)或动态(即代码)声明此类模型的最佳方式是什么?
我最终使用以下 classes 获得了结果(为简化起见,我忽略了模式处理、绑定和转换)。
但是,它依赖于在 jOOQ 包中注入自定义 class 并重用内部代码。这会导致安全(如果 JAR/包被密封)和可维护性问题。这就是为什么我不认为它是有效但可能的问题答案
jOOQ 破解:
package org.jooq.impl
public abstract class Projection<R extends Record> extends TableImpl<R> {
public static final <R extends Record, T> TableField<R, T> newField(String name, DataType<T> type, Table<R> table) {
return newField(name, type, table, null, null, null);
}
public static final <R extends Record, T, X, U> TableField<R, U> newField(String name, DataType<T> type, Table<R> table, String comment, Converter<X, U> converter, Binding<T, X> binding) {
final Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
@SuppressWarnings("unchecked")
final DataType<U> actualType =
converter == null && binding == null
? (DataType<U>) type
: type.asConvertedDataType(actualBinding);
final TableFieldImpl<R, U> tableField = new TableFieldImpl<R, U>(name, actualType, table, comment, actualBinding);
return tableField;
}
protected Projection(String name) {
this(name, null);
}
protected Projection(String name, Table<R> aliased) {
super(name, null, aliased);
}
protected <T> TableField<R,T> field(String name, DataType<T> type) {
return newField(name, type, this);
}
protected <T,F extends Field<T>> F add(F field) {
fields0().add(field);
return field;
}
protected Fields<R> getFields() {
return fields0();
}
}
我对常见问题的抽象:
package com.company.model.jooq;
public abstract class MyProjection<R extends Record> extends Projection<R> {
/**
* Unique version identifier for serialization.
*/
private static final long serialVersionUID = 1L;
protected Field<String> trimmed(String name) {
return DSL.trim(newField(name, SQLDataType.VARCHAR, this)).as(name);
}
protected Field<String> joined(String name, String... names) {
@SuppressWarnings("unchecked")
Field<String>[] fields = new Field[names.length];
for (int i = 0; i < names.length; i++) {
fields[i] = newField(names[i], SQLDataType.VARCHAR, this);
}
return DSL.trim(DSL.concat(fields)).as(name);
}
protected Field<Timestamp> timestamp(String suffix) {
return DSL.function("timestamp", SQLDataType.TIMESTAMP,
newField("DT_" + suffix, SQLDataType.DATE, this),
newField("TI_" + suffix, SQLDataType.TIME, this)
).as("TS_" + suffix);
}
protected MyProjection(String name) {
super(name);
}
protected MyProjection(String name, Table<R> aliased) {
super(name, aliased);
}
}
一个table模型示例:
package com.company.model.jooq;
public class MyProjectedTable extends MyProjection<Record> {
public final TableField<Record, Integer> ID = add(field("ID", SQLDataType.INTEGER));
public final Field<Timestamp> TS_CREATE = add(timestamp("CREATE"));
public final Field<Timestamp> TS_UPDATE = add(timestamp("UPDATE"));
public final TableField<Record, String> NAME = add(field("NAME", SQLDataType.VARCHAR));
public final Field<String> LABEL = add(trimmed("LABEL"));
public final Field<String> COMMENT = add(joined("COMMENT", "COMMENT1", "COMMENT2", "COMMENT3"));
}
在 JPA 中,您尝试做的是使用 @Embedded
annotation. Or in Hibernate - with a bit more sophistication, the 注释建模。 jOOQ 在路线图上有类似的功能:
- 实施"jOOQ views":https://github.com/jOOQ/jOOQ/issues/1969
- 支持 SQL 中的嵌套记录:https://github.com/jOOQ/jOOQ/issues/2360
- 支持"fetch groups":https://github.com/jOOQ/jOOQ/issues/2530
从 jOOQ 3.5 开始,您必须自己实现此支持。 看起来非常(重新)有用。
我正在使用设计非常糟糕的数据库,我需要在编写查询之前重新调整表格。
以下是我的常见问题:
- 时间戳已分为两列(一列用于日期,另一列用于时间)。
- 一些字符串列也被拆分成多个列。
- 大多数字符串都有固定长度和空白填充,所以我需要 trim 它们。
我首先考虑调整 Jooq 生成器的输出。但是查看 createField(...)
方法,它将字段附加到包私有的 fields0()
。这使得 SELECT *
查询所有(且仅)"raw" 个字段,而不是重新整形的字段。
静态(即class/member)或动态(即代码)声明此类模型的最佳方式是什么?
我最终使用以下 classes 获得了结果(为简化起见,我忽略了模式处理、绑定和转换)。
但是,它依赖于在 jOOQ 包中注入自定义 class 并重用内部代码。这会导致安全(如果 JAR/包被密封)和可维护性问题。这就是为什么我不认为它是有效但可能的问题答案
jOOQ 破解:
package org.jooq.impl
public abstract class Projection<R extends Record> extends TableImpl<R> {
public static final <R extends Record, T> TableField<R, T> newField(String name, DataType<T> type, Table<R> table) {
return newField(name, type, table, null, null, null);
}
public static final <R extends Record, T, X, U> TableField<R, U> newField(String name, DataType<T> type, Table<R> table, String comment, Converter<X, U> converter, Binding<T, X> binding) {
final Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
@SuppressWarnings("unchecked")
final DataType<U> actualType =
converter == null && binding == null
? (DataType<U>) type
: type.asConvertedDataType(actualBinding);
final TableFieldImpl<R, U> tableField = new TableFieldImpl<R, U>(name, actualType, table, comment, actualBinding);
return tableField;
}
protected Projection(String name) {
this(name, null);
}
protected Projection(String name, Table<R> aliased) {
super(name, null, aliased);
}
protected <T> TableField<R,T> field(String name, DataType<T> type) {
return newField(name, type, this);
}
protected <T,F extends Field<T>> F add(F field) {
fields0().add(field);
return field;
}
protected Fields<R> getFields() {
return fields0();
}
}
我对常见问题的抽象:
package com.company.model.jooq;
public abstract class MyProjection<R extends Record> extends Projection<R> {
/**
* Unique version identifier for serialization.
*/
private static final long serialVersionUID = 1L;
protected Field<String> trimmed(String name) {
return DSL.trim(newField(name, SQLDataType.VARCHAR, this)).as(name);
}
protected Field<String> joined(String name, String... names) {
@SuppressWarnings("unchecked")
Field<String>[] fields = new Field[names.length];
for (int i = 0; i < names.length; i++) {
fields[i] = newField(names[i], SQLDataType.VARCHAR, this);
}
return DSL.trim(DSL.concat(fields)).as(name);
}
protected Field<Timestamp> timestamp(String suffix) {
return DSL.function("timestamp", SQLDataType.TIMESTAMP,
newField("DT_" + suffix, SQLDataType.DATE, this),
newField("TI_" + suffix, SQLDataType.TIME, this)
).as("TS_" + suffix);
}
protected MyProjection(String name) {
super(name);
}
protected MyProjection(String name, Table<R> aliased) {
super(name, aliased);
}
}
一个table模型示例:
package com.company.model.jooq;
public class MyProjectedTable extends MyProjection<Record> {
public final TableField<Record, Integer> ID = add(field("ID", SQLDataType.INTEGER));
public final Field<Timestamp> TS_CREATE = add(timestamp("CREATE"));
public final Field<Timestamp> TS_UPDATE = add(timestamp("UPDATE"));
public final TableField<Record, String> NAME = add(field("NAME", SQLDataType.VARCHAR));
public final Field<String> LABEL = add(trimmed("LABEL"));
public final Field<String> COMMENT = add(joined("COMMENT", "COMMENT1", "COMMENT2", "COMMENT3"));
}
在 JPA 中,您尝试做的是使用 @Embedded
annotation. Or in Hibernate - with a bit more sophistication, the
- 实施"jOOQ views":https://github.com/jOOQ/jOOQ/issues/1969
- 支持 SQL 中的嵌套记录:https://github.com/jOOQ/jOOQ/issues/2360
- 支持"fetch groups":https://github.com/jOOQ/jOOQ/issues/2530
从 jOOQ 3.5 开始,您必须自己实现此支持。