Jooq 与 POJO 转换器

Posted

技术标签:

【中文标题】Jooq 与 POJO 转换器【英文标题】:Jooq with POJO Converter 【发布时间】:2021-02-24 14:33:51 【问题描述】:

我正在尝试在 Jooq 的帮助下实现一个软件来读取和写入 h2 数据库中的数据。 我的 PLC_DATA 表有一个带有 TIMESTAMP 的列,该列通常映射到 LocalDateTime 但我需要将此数据映射到 POJO 中的 Instant,所以我编写了自定义转换器:

public class TimestampConverter implements Converter<LocalDateTime, Instant> 

    private static final long serialVersionUID = -2866811348870878385L;

    /**
     * Convert a @code LocalDateTime into @code Instant
     */
    @Override
    public Instant from(LocalDateTime databaseObject) 
        return databaseObject.toInstant(ZoneOffset.UTC);
    

    /**
     * Convert a @code Instant into @code Timestamp
     */
    @Override
    public LocalDateTime to(Instant userObject) 
        return userObject.atZone(ZoneOffset.UTC).toLocalDateTime();
    

    /**
     * Return the from Type Class
     */
    @Override
    public Class<LocalDateTime> fromType() 
        return LocalDateTime.class;
    

    /**
     * Return the to Type Class
     */
    @Override
    public Class<Instant> toType() 
        return Instant.class;
    

并且我在我的build.gradle 文件中引用了forcedType:

forcedType 
    userType = 'java.time.Instant'
    converter = 'it.fox.plcwebgui.utils.db.TimestampConverter'                      
    includeTypes = 'TIMESTAMP.*'

我已经注释了我的 POJO:

public class PlcEventBean implements Serializable 

    private static final long serialVersionUID = 1988924276212981713L;

    @Column(name = "ID")
    public long id = 0;

    @Column(name = "EVENT_INSTANT")
    public Instant eventInstant = Instant.ofEpochMilli(0);

    @Column(name = "MAX_FORCE")
    private int maxForce;

    /**
     * Get the Event ID
     * @param id the id
     */
    public long getId() 
        return id;
    

    /**
     * Set the Event ID
     * @param id the id
     */
    public void setId(long id) 
        this.id = id;
    

    /**
     * The instant (in GMT) of the event
     * @return the instant of the event
     */
    public Instant getEventDate() 
        return eventInstant;
    

    /**
     * Set the instant of the Event
     * @param eventInstant the instant to set
     */
    public void setEventDate(Instant eventInstant) 
        this.eventInstant = eventInstant;
    

    /**
     * The max Force used for the event
     * @return the max force used
     */
    public int getMaxForce() 
        return maxForce;
    

    /**
     * Set the max force used for the Event
     * @param maxForce the value of the max force
     */
    public void setMaxForce(int maxForce) 
        this.maxForce = maxForce;
    

当我从数据库读取到我的 POJO 时,代码就像这里一样:

public List<PlcEventBean> fetchData(int offset, int limit, DataFilter filter) 
    Instant fromInstant = filter.getFromInstant();
    Instant toInstant = filter.getToInstant();
    String id  = filter.getId();
    List<PlcEventBean> plcEventBeans = context.select()
        .from(PLC_DATA)
        .where(
            PLC_DATA.EVENT_INSTANT.greaterThan(fromInstant)
                                    .and(PLC_DATA.EVENT_INSTANT.lessThan(toInstant))
                                    .and(PLC_DATA.ID.like("%" + id + "%"))
            )
            .offset(offset)
            .limit(limit)
            .fetchInto(PlcEventBean.class);
    logger.info("Fetched  with offset:  limit:  with fromDateTime , toDateTime , textSearch "
        ,plcEventBeans.size()
        ,offset
        ,limit
        ,fromInstant
        ,toInstant
        ,id
    );
    return plcEventBeans;

但是当我尝试在数据库中写入一些数据时,我在尝试生成新记录时遇到了异常:

public void generateRandomValues() 
    int nEvents = 40000;
    Random r = new Random(0);
    List<PlcEventBean> plcEvents = new ArrayList<>();

    for (long i = 0; i < nEvents; i++) 
        PlcEventBean eventBean = new PlcEventBean();
        eventBean.setId(i);
        eventBean.setEventDate(Instant.now().plus(i, ChronoUnit.MINUTES));
        eventBean.setMaxForce(Math.abs(r.nextInt()));
        plcEvents.add(eventBean);
    
    PlcDataRecord plcDataRecord = context.newRecord(PLC_DATA, plcEvents);
    context.executeInsert(plcDataRecord);

org.jooq.exception.DataTypeException: Cannot convert from it.fox.plcwebgui.plc.PlcEventBean@2a389173 (class it.fox.plcwebgui.plc.PlcEventBean) to class java.time.LocalDateTime
    at org.jooq.tools.Convert$ConvertAll.fail(Convert.java:1200)
    at org.jooq.tools.Convert$ConvertAll.from(Convert.java:1089)
    at org.jooq.tools.Convert.convert0(Convert.java:324)
    at org.jooq.tools.Convert.convert(Convert.java:316)
    at org.jooq.tools.Convert.convert(Convert.java:387)
    at org.jooq.impl.DefaultDataType.convert(DefaultDataType.java:827)
    at org.jooq.impl.ConvertedDataType.convert(ConvertedDataType.java:114)
    at org.jooq.impl.Tools.setValue(Tools.java:2823)
    at org.jooq.impl.DefaultRecordUnmapper$IterableUnmapper.unmap(DefaultRecordUnmapper.java:189)
    at org.jooq.impl.DefaultRecordUnmapper.unmap(DefaultRecordUnmapper.java:102)
    at org.jooq.impl.AbstractRecord.from0(AbstractRecord.java:837)
    at org.jooq.impl.AbstractRecord.from(AbstractRecord.java:867)
    at org.jooq.impl.DefaultDSLContext$6.operate(DefaultDSLContext.java:4019)
    at org.jooq.impl.RecordDelegate.operate(RecordDelegate.java:130)
    at org.jooq.impl.DefaultDSLContext.newRecord(DefaultDSLContext.java:4015)
    at it.fox.plcwebgui.plc.PlcEventServiceDatabaseImp.generateRandomValues(PlcEventServiceDatabaseImp.java:120)
    at it.fox.plcwebgui.utils.db.PlcEventServiceDatabaseImpTest.generateRandomValuesTest01(PlcEventServiceDatabaseImpTest.java:128)

据我在文档中了解,Converter 应该双向工作。 我错过了什么?

问候,

斯特凡诺

【问题讨论】:

【参考方案1】:

错误就在这里:

PlcDataRecord plcDataRecord = context.newRecord(PLC_DATA, plcEvents);

您想将 pojo 列表转换为单个记录,这没有意义。将这个逻辑移到你的循环中,而不是:

List<PlcDataRecord> records = new ArrayList<>();

for (long i = 0; i < nEvents; i++) 
    PlcEventBean eventBean = new PlcEventBean();
    eventBean.setId(i);
    eventBean.setEventDate(Instant.now().plus(i, ChronoUnit.MINUTES));
    eventBean.setMaxForce(Math.abs(r.nextInt()));
    records.add(context.newRecord(PLC_DATA, eventBean));


context.batchInsert(records);

旁注

只需将您的类型重写为SQLDataType.INSTANT,而不是滚动您自己的转换器:

forcedType 
    name = 'INSTANT'
    includeTypes = 'TIMESTAMP.*'

【讨论】:

谢谢!!!我的错,对不起;很容易。也谢谢你的建议。 @StefanoBossi:这是最好的 :)

以上是关于Jooq 与 POJO 转换器的主要内容,如果未能解决你的问题,请参考以下文章

使用 JOOQ 从 POJO 设置字段为空

JOOQ 使用内联转换器将字符串转换为枚举

JOOQ 使用转换器将字符串转换为枚举

JOOQ多字段自定义类型转换器

JOOQ 生成 pojo 缺少 GeneratedValue 注释

jOOQ 自定义 Pojo 和 DAO 生成