使用 JOOQ 在 java.sql.Timestamp 和 java.time.Instant 之间转换时遇到问题
Posted
技术标签:
【中文标题】使用 JOOQ 在 java.sql.Timestamp 和 java.time.Instant 之间转换时遇到问题【英文标题】:Trouble converting between java.sql.Timestamp & java.time.Instant with JOOQ 【发布时间】:2022-01-09 18:10:55 【问题描述】:我在使用 JOOQ 转换器在 java.sql.Timestamp 和 java.time.Instant 之间转换时遇到问题。
这是我正在使用的代码的简化版本。
public class User
private static final Converter<Timestamp, Instant> MY_CONVERTER= Converter.of(
Timestamp.class,
Instant.class,
t -> t == null ? null : t.toInstant(),
i -> i == null ? null : Timestamp.from(i)
)
public static Table<?> table = DSL.table("user");
public static Field<String> name = DSL.field(DSL.name(table.getName(), "name"), String.class);
public static Field<Instant> name = DSL.field(DSL.name(table.getCreated(), "created"), SQLDataType.TIMESTAMP.asConvertedDataType(Converter.of(MY_CONVERTER)));
private class UserDto
private String name;
private Instant created;
// getters, setters, etc.
public class UserWriter
// constructor with injected DefaultDSLContext etc..
public void create(UserDto user)
dslContext.insertInto(User.table, User.firstName, User.lastName)
.values(user.getName(), user.getCreated())
.execute();
public class UserReader
// constructor with injected DefaultDSLContext etc..
public Result<Record> getAll()
return dslContext.select().from(User.table).fetch();
public class UserService
// constructor with injected UserReader etc..
public Collection<UserDto> getAll()
return userReader
.getAll()
.stream()
.map(Users::from)
.collect(Collectors.toList());
public class Users
public static UserDto from(Record record)
UserDto user = new UserDto();
user.setName(record.get(User.name));
user.setCreated(record.get(User.created);
return user;
当我创建一个新用户时,转换器被调用并且插入工作正常。但是,当我选择用户时,不会调用转换器,并且 Users::from
方法中的 record.get(User.created)
调用会返回一个时间戳(因此会失败,因为 UserDto.setCreated 需要一个 Instant)。
有什么想法吗?
谢谢!
【问题讨论】:
更新:似乎问题在于(当我指定要选择的字段时,会调用转换器)。所以我的问题是,如果我想检索所有字段并执行转换,我是否需要在 select(à 中指定所有字段或者是否有另一种不那么冗长的方式? 能否请您发布SELECT
声明?
【参考方案1】:
为什么没有应用转换器
从您提出问题的方式来看(您没有发布您尝试过的确切 SELECT
语句),我假设您没有明确传递所有列表达式。但是,jOOQ 怎么能找出你的表有哪些列呢?您在 some 类中声明了 some 列表达式,但该类不遵循 jOOQ 已知的任何结构。让 jOOQ 获取所有 已知 列的唯一方法是让 jOOQ 知道它们,使用代码生成(见下文)。
当然,您可以让User
扩展内部org.jooq.impl.TableImpl
类并使用内部API 来注册Field
值。但是,如果您可以生成此代码,为什么还要手动执行呢?
代码生成
我将重复上一个问题的要点,即:请使用code generator。 I've now written an entire article on why you should do this。一旦 jOOQ 通过代码生成知道了您的所有元数据,您就可以像这样自动选择所有列:
UserRecord user = ctx
.selectFrom(USER)
.where(USER.ID.eq(...))
.fetchOne();
不仅如此,您还可以使用<forcedType>
将数据类型配置为INSTANT
,这样您就不必每次都担心数据类型转换。
对此我怎么强调都不为过,而且我经常感到惊讶的是,有多少项目试图在没有代码生成的情况下使用 jOOQ,这消除了 jOOQ 的大部分功能。 不使用代码生成的主要原因是如果您的架构是动态的,但由于您有 User
类,它显然不是动态的。
【讨论】:
是的,我自己得出了这个结论——尽管非常感谢您花时间解释!我对 JOOQ 不太熟悉(尽管我一直打算使用它一段时间),这是一个现有项目,我目前无法完成重新布线(由于时间限制)但是我会当我有时间的时候一定会研究一下。 @AnthonyWebster 您不必一次性重写所有内容。您可以通过查询迁移查询,因为无论如何您都必须触摸它们。设置代码生成一开始会产生一些额外的开销,但随后,您的工作会得到很大改进,并且您会更有效率。 @AnthonyWebster:因为这个代码生成问题是一个常见的话题,堆栈溢出问题是关于代码生成不会发生的问题,see e.g. this one,我现在写了a more complete article about the many benefits of using the code generator以上是关于使用 JOOQ 在 java.sql.Timestamp 和 java.time.Instant 之间转换时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章
使用 jOOQ 在 PostgreSQL 中进行 UPSERT
无法使用 gradle-jooq-plugin-3.0.1、jooq-3.11.2 找到或加载主类 org.jooq.codegen.GenerationTool