Jooq 与 POJO 转换器
Jooq with POJO Converter
我正在尝试在 Jooq 的帮助下实现一个软件来将数据读写到 h2 数据库中。
我的 PLC_DATA Table 有一个包含 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.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
应该双向工作。
我错过了什么?
此致,
斯特凡诺
错误在这里:
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.*'
}
我正在尝试在 Jooq 的帮助下实现一个软件来将数据读写到 h2 数据库中。 我的 PLC_DATA Table 有一个包含 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.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
应该双向工作。
我错过了什么?
此致,
斯特凡诺
错误在这里:
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.*'
}