使用 JOOQ 在 java.sql.Timestamp 和 java.time.Instant 之间转换时遇到问题

Trouble converting between java.sql.Timestamp & java.time.Instant with JOOQ

我在使用 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;
    }
}

当我创建一个新用户时,转换器被调用并且插入工作正常。但是,当我 select 用户未调用转换器并且 record.get(User.created)Users::from 方法中调用 returns 时间戳(因此失败,因为 UserDto.setCreated需要 Instant)。

有什么想法吗?

谢谢!

为什么没有应用转换器

从您表述问题的方式来看(您没有 post 您尝试过的确切 SELECT 陈述),我假设您没有通过所有列表达式明确地。但是,jOOQ 如何才能找出你的 table 有哪些列呢?您在 some class 中声明了 some 列表达式,但是 class 不遵循 jOOQ 已知的任何结构。让 jOOQ 获取所有 known 列的唯一方法是让 jOOQ 知道它们,使用代码生成(见下文)。

当然,您可以让 User 扩展内部 org.jooq.impl.TableImpl class 并使用内部 API 来注册 Field 值。但是,如果可以生成此代码,为什么要手动执行此操作?

代码生成

我将重复我上一个问题的要点,即:请使用code generator. I've now written an entire article on why you should do this。一旦 jOOQ 通过代码生成知道了所有的元数据,你就可以像这样自动 select 所有列:

UserRecord user = ctx
    .selectFrom(USER)
    .where(USER.ID.eq(...))
    .fetchOne();

不仅如此,您还可以使用 <forcedType> 将您的数据类型配置为 INSTANT,因此您无需每次都担心数据类型转换。

我怎么强调都不为过,而且我经常感到惊讶的是有多少项目试图在没有代码生成的情况下使用 jOOQ,这会削弱 jOOQ 的强大功能。 使用代码生成的主要原因是如果你的模式是动态的,但既然你有Userclass,它显然不是动态的。