如何使用 jOOQ fetchInto() 映射到现有的 Hibernate 模型?

Posted

技术标签:

【中文标题】如何使用 jOOQ fetchInto() 映射到现有的 Hibernate 模型?【英文标题】:How to map to an existing Hibernate model using jOOQ fetchInto()? 【发布时间】:2021-07-27 15:39:49 【问题描述】:

我正在尝试使用 jOOQ fetchInto() 方法映射到现有的 Hibernate 模型 Organization(类及其继承如下)。

Organization organization = jooq().select().from(ORGANIZATION).fetchOne().into(Organization.class);

我的问题是我无法真正理解DefaultRecordMapper 中发生了什么,因为我觉得我并不完全熟悉所使用的所有术语。我试图弄清楚它如何应用于我的代码库中的 Hibernate 类。

到目前为止我已经尝试过:

使用 jOOQ 生成的 POJO 来查看它是否完全检索和映射数据(有效)。 向Organization Hibernate 模型添加构造函数、getter 和setter。 在Organization Hibernate 模型中将@Column 注释添加到name

什么有效:

id 字段已正确映射。

什么不起作用:

name 字段未映射 (null)。 createdAtmodifiedAt 字段未映射 (null)。

我的问题是:在映射中我是否忽略了一些东西?关于 Hibernate 模型的类、字段、构造函数和注释,我应该注意什么?我想最终映射代码库中的所有 Hibernate 模型并使用 fetchInto 来做到这一点。

谢谢! :)

@Entity
public class Organization extends BaseModel 
  @Required public String name;

  //... a lot of other code

@MappedSuperclass
public class BaseModel extends Model 
  /** The datetime this entity was first saved. Automatically set by a JPA prePersist */
  @NoBinding
  @Column
  @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
  public DateTime createdAt;

  /** The datetime this entity was last modified. Automatically set by a JPA preUpdate */
  @NoBinding
  @Column
  @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
  public DateTime modifiedAt;

  //...

@MappedSuperclass
public class Model extends GenericModel  // Both Model and GenericModel are from the Play Framework
    @Id
    @GeneratedValue
    public Long id;

    public Model() 
    

    public Long getId() 
        return this.id;
    

    public Object _key() 
        return this.getId();
    

【问题讨论】:

为什么需要映射到 Hibernate 实体?向后兼容?更快的迁移路径?还是因为您想通过实体管理器再次持久化更改? 所以基本上向后兼容模型中存在的大量方法。因此,您对链接的初步回答可能是我目前解决此问题的最佳选择。 有道理。我假设这些方法包含业务逻辑。我认为这也不是 JPA 所推荐的,所以也许作为第一个重构步骤,您可以将它们移出实体,而与使用 jOOQ 无关?我已经更新了我的答案,并提示了 name 列上的问题。 是的,很多业务逻辑。现在它通过将现有的字符串查询转换为 jOOQ 查询来使用 jOOQ,但让它由 Hibernate 执行。逻辑上应该遵循进一步的重构步骤。感谢大家的帮助! 【参考方案1】:

jOOQ 不支持所有许多 JPA 和 Hibernate 特定的注释。从历史上看,它支持一些 JPA 注释(因为为什么不支持),但是完全互操作会过度,并且会将产品开发时间投入错误的地方。 jOOQ 绝不是 JPA 实现。

第 0 步:为什么(某些)映射不起作用?

如前所述,并非所有 JPA 规范都已实现。例如,一个已知问题是 @Column 注释在 jOOQ 中仍然是强制性的: https://github.com/jOOQ/jOOQ/issues/4586

可能还有其他此类限制,这可能被视为错误。如果您想继续走这条路,请随时报告他们:https://github.com/jOOQ/jOOQ/issues/new/choose

但是像 @MappedSuperclass@Type 这样的东西不太可能得到 jOOQ 的支持。

第 1 步:你真的需要它吗?

您已决定使用 jOOQ 创建和运行查询。我想您的 实际 查询比您显示的要复杂得多,因为对于该特定查询,您不需要 jOOQ。

您真的需要映射到 Hibernate 实体吗?因为即使您使用 Hibernate,推荐的方法是在您要修改实体并将增量存储回数据库时使用它们。如果是这种情况,请参阅下面的步骤 2。如果不是这样,为什么不使用 jOOQ 自己的映射功能来处理任何支持 jOOQ 的 POJO 样式?

第 2 步:使用 Hibernate 执行 jOOQ 查询

如果您仅使用 jOOQ 来构建一个相当复杂的 SQL 查询,并且您需要作为结果的 Hibernate 实体,那么use Hibernate to execute the jOOQ query as documented here。一个小实用程序就足够了:

public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, Class<E> type) 
    Query result = em.createNativeQuery(query.getSQL(), type);

    List<Object> values = query.getBindValues();
    for (int i = 0; i < values.size(); i++)
        result.setParameter(i + 1, values.get(i));

    return result.getResultList();

【讨论】:

感谢您的快速回答!事实上,SQL 查询要复杂得多(模型也是如此)。我想要一种使用 jOOQ 将它们映射到现有模型的方法,这样我就可以使用完整的模型及其方法,这样我就不必更改应用程序多层(瘦控制器、胖模型)上的数据结构。所以我真的需要 Hibernate 实体。但我也想删除对 Hibernate 的依赖来执行查询,但这显然现在似乎不可能,除非我更改应用程序的整个层。也许我稍后会做一些事情,哈哈。 @Bram:著名的“后来者” :) 好吧,使用 Hibernate 执行查询将是目前侵入性最小的更改。您不必一次性迁移所有内容。 哈哈,是的,我现在要走那条干扰最小的路径。希望我会一步一步地让 jOOQ 更多地进入代码库。美丽的图书馆!

以上是关于如何使用 jOOQ fetchInto() 映射到现有的 Hibernate 模型?的主要内容,如果未能解决你的问题,请参考以下文章

如果字段为空,则 Jooq fetchInto 具有默认值

JOOQ 连接两个具有相同列名的表

如何将 2 条记录(多对一)的 Result 对象映射到 jOOQ 中它们各自的记录对象中?

将 jooq 中的获取/结果映射到特定记录

如何将2条记录(多对一)的Result对象映射到jOOQ中各自的记录对象?

JOOQ:根据长度将 tinyint 映射到布尔值