1

jOOQ可以在select子句中自动为表的所有列添加别名前缀吗?

jOOQ 还可以帮助解决数据库的 128 字节/字符名称长度限制吗?


问题的原因是 SimpleFlatMapper 用于映射。SimpleFlatMapper 需要将获取的数据库列名映射到模型。

模型示例(真正使用 getter/setter):

class Head {
    public Integer id;
    public List<Position> positions;
    ...
}
class Position {
    public Integer id;
    public Integer headId;
    ...
}

命名可以单独完成:

ResultSet resultSet = dsl.select(..., POSITION.ID.as("positions_id"), ...)
    .from(HEAD)
    .join(POSITION.as("positions")).onKey()
    .fetchResultSet();
    
List<Head> headers = JdbcMapperFactory.newInstance()
                                      .ignorePropertyNotFound()
                                      .newMapper(Head.class)
                                      .stream(resultSet)
                                      .collect(Collectors.toList())

但是,如果它是具有多个连接/列的复杂模型,则有点乏味。我找到的唯一解决方案是手动编写函数。但是,我是否可能忽略了某些事情,而 jOOQ 可以自己完成还是提供帮助?

像这样的东西会非常好(可能不是最好的命名,我当场想不出更好的东西):

ResultSet resultSet = dsl.select()
    .from(HEAD)
    .join(POSITION.as("positions").prefixColumns()).onKey()
    .fetchResultSet();

或者:

ResultSet resultSet = dsl.selectWithTableAlias()
    .from(HEAD)
    .join(POSITION.as("positions")).onKey()
    .fetchResultSet();

产生以下 SQL:

SELECT head.id, head.***, positions.id AS positions_id, positions.headid AS positions_headid, positions.***
FROM head JOIN position AS positions ON head.id = positions.headid

此外,Oracle 和 MSSQL 等数据库的名称限制为 128 个字节/字符。在非常罕见的复杂场景中,由于需要嵌套,别名可能会达到该限制。

jOOQ 不能以某种形式为此提供解决方法,或者可以吗?所以基本上定义一个在 SQL 中使用的名称和一个实际结果对象的名称。

我知道,非常小众的要求。但他们会对映射有很大帮助。

4

1 回答 1

1

jOOQ可以在select子句中自动为表的所有列添加别名前缀吗?

没有这样的功能,因为所需的自动前缀算法的可能集非常大,并且 jOOQ 最终不会完全按照您的意愿行事。也许,将来有 SPI 可以帮助您做到这一点。但是还没有一个可用的:https ://github.com/jOOQ/jOOQ/issues/11545

但是,您可以自己轻松地做到这一点,因为每个 jOOQ 查询只是一个动态构造的表达式树,即使您并不总是将 jOOQ 用于动态 SQL

您可以轻松编写实用程序并在任何地方使用它:

public static List<Field<?>> autoPrefix(Field<?>... fields) {
    return autoprefix(Arrays.asList(fields));
}

public static List<Field<?>> autoPrefix(Field<?>... fields) {
    Stream.of(fields).map(f -> f.as(myPrefixLogic(f))).collect(toList());
}

现在可以在所有DSLContext.select()调用中显式使用它,例如

dsl.select(autoPrefix(..., POSITION.ID.as("positions_id"), ...))
    .from(HEAD)
    .join(POSITION.as("positions")).onKey()
    .fetchResultSet();

或者,您可以将查询包装在派生表中:

public ResultSet fetchResultSetWithPrefix(Select<?> select) {
    Table<?> table = select.asTable("t");

    return
    dsl.select(autoPrefix(table.fields()))
       .from(table)
       .fetchResultSet();
}

现在,fetchResultSet()您无需调用 ,而是调用辅助函数:

try (ResultSet rs = fetchResultSetWithPrefix(
    dsl.select(..., POSITION.ID.as("positions_id"), ...)
       .from(HEAD)
       .join(POSITION.as("positions")).onKey()
)) {
    ...
}

另一个更复杂的选择是使用VisitListener.

请记住,无论您的查询是什么样子(因为 jOOQ 的 DSL 在语法上模仿 SQL),您的所有jOOQ 查询都是动态 SQL 查询,因此您可以相对轻松地将它们自动转换为您想要的任何内容。

jOOQ 还可以帮助解决数据库的 128 字节/字符名称长度限制吗?

对于这种自动性,我会像以前一样持保留态度。你会在哪里看到 jOOQ 在这里提供自动帮助?给定您的命名方案 ( table_column),您希望每个对象类型公平分配 63 个字符吗?还是表不如列重要,您会将表名截断为 42 个字符,为列留下 85 个字符?

如果您想完全限定标识符,包括模式名称,如 中所示,该schema_table_column怎么办?如果你投射 UDT 会怎样,这意味着你会得到schema_table_column_attribute1_attribute2

我认为 jOOQ 无法提供任何满足所有需求的自动化。但是,如上所示,为整个应用程序只实现一次非常简单,确保始终正确应用命名。如果 SPI 可用,您可以在那里实现您的缩写逻辑。

于 2021-03-01T07:51:02.140 回答