【问题标题】:jOOQ - DefaultRecordMapper - ListjOOQ - DefaultRecordMapper - 列表
【发布时间】:2021-05-22 07:36:59
【问题描述】:

DefaultRecordMapper 可以处理列表吗?

模型示例(确实使用了getter/setter):

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

我首先用一个简单的选择来尝试它:

dsl.select()
    .from(HEAD)
    .join(POSITION).onKey()
    .fetchInto(Head.class);

我也尝试过使用嵌套语法,但它不起作用:

dsl.select(..., POSITION.ID.as("positions.id"), ...)
    .from(HEAD)
    .join(POSITION).onKey()
    .fetchInto(Head.class);

列表永远不会被初始化。我不确定我是否做错了什么。 DefaultRecordMapper 可以做到这一点吗?

我知道 jOOQ 提供了像“intoGroups”这样的功能。 然而,这意味着我们公司不能使用我们现有的模型。

或者在这种情况下是否需要像 ModelMapper 这样的第三方库?

提前非常感谢!

【问题讨论】:

  • 你使用的是什么 SQL 方言?
  • 我没有定义它。所以它应该是默认的(独立于数据库)。

标签: java sql jooq


【解决方案1】:

嵌套集合的推荐方法

jOOQ 中对嵌套集合的开箱即用支持是通过 SQL/XML 或 SQL/JSON,这取决于在您的 SQL 方言中最有效的方式。

从 jOOQ 3.14 开始,它作为一个 API 提供,您可以直接使用它,在 jOOQ 3.15 中,添加了新的 MULTISETMULTISET_AGG 函数以保持序列化格式对您的代码透明,并重新添加类型安全,see also this blog post

直接使用 jOOQ 3.14 SQL/XML 和 SQL/JSON

这个想法是您直接在 SQL 中嵌套集合,将结果序列化为 XML 或 JSON,并在幕后使用 JAXB(用于 XML)或 Gson 或 Jackson(用于 JSON)将文档映射到 Java 的层次结构类。只要您的类路径中有 JAXB、Gson 或 Jackson,所有这些都非常简单和自动。

数据结构示例:

dsl.select(
      HEAD.ID,
      field(
        select(jsonArrayAgg(jsonObject(
          key("id").value(POSITION.ID),
          key("x").value(POSITION.X), ...
        )))
        .from(POSITIONS)
        .where(POSITIONS.HEAD_ID.eq(HEAD.ID))
      ).as("positions")
    )
    .from(HEAD)
    .fetchInto(Head.class);

此处记录了更多示例:

请注意,JSON_ARRAYAGG() 将空集聚合到 NULL,而不是空集 []If that's a problem, use COALESCE()

使用 jOOQ 3.15 MULTISET

从 jOOQ 3.15 开始,建议使用MULTISET。您的查询现在看起来像这样(所有类型都是安全的!):

dsl.select(
      HEAD.ID,
      multiset(
        select(POSITION.ID, POSITION.X, ...)
        .from(POSITIONS)
        .where(POSITIONS.HEAD_ID.eq(HEAD.ID))
      ).convertFrom(r -> r.map(Records.mapping(Position::new)))
    )
    .from(HEAD)
    .fetch(Records.mapping(Head::new));

以上假设您的类型 in order to profit from the new ad-hoc converter features 具有适当的构造函数。

其他选项

还有一些第三方可以帮助简化映射到嵌套集合的任务,包括:

或者,在某种程度上,您可以使用 jOOQ 的各种内置方法,包括 Result.intoGroups() 或 JDK Collector 基于 ResultQuery.collect() 的许多重载,它们更具可组合性。

这些方法中的大多数仅在一定程度上有效,因为它们都基于对连接表产生的平面、非规范化结果集进行去重。直接在 SQL 中嵌套集合对于任意目标模型要强大得多,所以如果你让它工作,它会工作得更好。

【讨论】:

  • 谢谢!我检查过。 Oracle 从 12.2.0.1.0 开始支持 JSON_OBJECT。 SQL Server 自 2016 版起支持 FOR JSON。对于 H2,我根本找不到自从添加 JSON_OBJECT 以来的信息。你知道吗?这些是我们公司支持/使用的数据库。不幸的是,我们的客户也可以使用旧版本,因为我们基于数据库制造商的延长寿命支持。所以我需要澄清它是否仍然是一种选择。
  • 根据jOOQ手册,XML函数只支持Oracle(与上面提到的3个dbs有关)。它是否正确? SQL 服务器本身似乎在所有版本中都支持 FOR XML(请参阅docs.microsoft.com/en-us/sql/relational-databases/xml/…)。
  • H2 非常活跃,包括补丁版本之间微妙的向后不兼容。我已经停止跟踪 H2 版本,只担心最新版本。我很好奇支持旧 H2 版本的理由。对于 SQL Server 和 Oracle,XML API 可以提供帮助。使用当前的 jOOQ 版本,您必须自己为 Oracle/SQL Server 特定的 XML 生成很多内容。未来的版本将对此提供更统一的视图:github.com/jOOQ/jOOQ/issues/11487 甚至更好的嵌套集合:github.com/jOOQ/jOOQ/issues/3884
  • @db2222:但是,这只是嵌套复杂集合的推荐方法,目前,我将使用其他选项更新我的答案。如果这对您来说似乎是最好的前进方式,我们很可能会在不久的将来重新确定一些改进的优先级
  • 再次干杯 :-) 您的响应时间和质量非常出色!经过分析,JSON/XML 对我们来说似乎不是一个好的解决方案。看起来 SimpleFlatMapper 是我们案例的最佳选择。然而出现了一些问题。我会为此开一个新的。
猜你喜欢
  • 2019-09-02
  • 2020-08-04
  • 2017-06-09
  • 2020-08-28
  • 2015-11-26
  • 2018-03-24
  • 2016-02-12
  • 2016-09-21
  • 2017-12-13
相关资源
最近更新 更多