【问题标题】:Table re-shaping表格重塑
【发布时间】:2015-02-07 15:48:30
【问题描述】:

我正在使用设计非常糟糕的数据库,我需要在编写查询之前重新调整表格。

以下是我的常见问题:

  • 时间戳分为两列(一列用于日期,另一列用于时间)。
  • 一些字符串列也被拆分为多个列。
  • 大多数字符串都有固定长度和空白填充,所以我需要修剪它们。

我首先考虑的是调整 Jooq Generator 的输出。但是查看createField(...) 方法,它将字段附加到fields0(),这是包私有的。这使得 SELECT * 查询所有(且仅)“原始”字段,而不是重新塑造的字段。

静态(即类/成员)或动态(即代码)声明此类模型的最佳方式是什么?

【问题讨论】:

  • 理想情况下,您将直接在数据库中编写视图。这是一个选择吗?
  • 当然,应该有。但不幸的是,在我的环境中,管理操作非常复杂。此外,查询定义非常不稳定,会随着时间而改变。
  • 我知道这种感觉。只是检查:)

标签: java jooq


【解决方案1】:

我最终使用以下类获得了结果(为了简化,我忽略了模式处理、绑定和转换)。

但是,它依赖于在 jOOQ 包中注入自定义类并重用内部代码。这可能会导致安全性(如果 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);
  }
}

表格模型示例:

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"));
}

【讨论】:

  • 有趣。您基本上实现了 Hibernate 的 @Formula 注释,或多或少...
  • 是的,我知道它打破了 jOOQ 成语,因为它不是 SQL。但我一直在寻找一个介于 jOOQ 和 ORM 之间的库: - 查询定义 - SQL 生成(对它有很好的控制) - 延迟获取(迭代,因为我需要浏览超过 50 万条记录) - 非静态输出模型(即实体) 我很确定我的需求比 ORM 更接近 jOOQ。所以,我开始玩jOOQ。我还应该编写普通查询(使用完整的 DSL API 功能),但是由于要加入的列数(>100)和表/查询(>8)的数量,查询构建应该很清楚。
  • 事实上,它并没有破坏“jOOQ idiom”。 jOOQ 有CustomTable 和其他类似用例的类型。只是,这些东西现在还很低级。我们有一个feature requests for views "written in jOOQ"。稍后我会写一个答案。
【解决方案2】:

在 JPA 中,您尝试使用 @Embedded 注释进行建模。或者在 Hibernate 中——更复杂一点,@Formula 注释。 jOOQ 在路线图上有类似的功能:

不过,从 jOOQ 3.5 开始,您必须自己实现此支持。 approach that you've chosen yourself 看起来非常(重新)有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    • 2018-05-07
    相关资源
    最近更新 更多