我目前正在使用JDBI将我的POJO保存到我的数据库中。我使用MS SQL Server作为我的数据库。我目前无法在表格中插入行,因为LocalDate
变量没有映射值存在问题。
scoreDate
字段为LocalDate
类型,不是强制性的,我没有为此字段传递任何值。但是在尝试运行以下测试时,我得到以下错误。
请您告知问题是什么以及如何解决?
测试类
@Test
public void testInsertClientScore() throws Exception {
final DBI dbi = databaseResource.getDBI();
final ClientScoreDao clientScoreDao = dbi.onDemand(ClientScoreDao.class);
final ClientScore clientScore = ImmutableClientScore.builder()
.id(1L)
.ClientName("TESTCLIENT")
.build();
assertEquals(1,clientScoreDao.insert(clientScore));
}
错误追踪
org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException: com.microsoft.sqlserver.jdbc.SQLServerException:
Implicit conversion from data type varbinary to date is not allowed. Use the CONVERT function to run this query. [statement:"insert into ICEBERG.ClientScore (scoreId, clientname, scoredate) values (:id, :ClientName, :scoreDate)", located:"insert into ICEBERG.ClientScore (scoreId, clientname, scoredate) values (:id, :ClientName, :scoreDate)", rewritten:"insert into ICEBERG.ClientScore (scoreId, clientname, scoredate) values (?, ?, ?)", arguments:{ positional:{}, named:{ClientName:'TESTCLIENT',id:1,scoreDate:null}, finder:[]}]
at org.skife.jdbi.v2.SQLStatement.internalExecute(SQLStatement.java:1338)
at org.skife.jdbi.v2.Update.execute(Update.java:56)
at org.skife.jdbi.v2.sqlobject.UpdateHandler$2.value(UpdateHandler.java:67)
.....
....
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Implicit conversion from data type varbinary to date is not allowed. Use the CONVERT function to run this query.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:217)
数据库表定义
-- ClientScore table
CREATE TABLE ICEBERG.ClientScore (
ScoreId INTEGER NOT NULL,
ClientName VARCHAR(50) NOT NULL,
ScoreDate DATE NULL,
CONSTRAINT PK_CLIENTSCORE_TEST PRIMARY KEY (ScoreId)
)
POJO
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.mercuria.dali.jdbi.Jdbi;
import com.mercuria.dali.jdbi.JdbiOptions;
import org.immutables.value.Value;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.time.LocalDate;
@Value.Immutable
@Jdbi(tableName = "ICEBERG.ClientScore")
@JsonSerialize(as = ImmutableClientScore.class)
@JsonDeserialize(as = ImmutableClientScore.class)
public interface ClientScore extends Serializable {
@JsonProperty("scoreid")
@JdbiOptions(columnName = "scoreId")
Long id();
@JsonProperty("clientname")
@JdbiOptions(columnName = "clientname")
String ClientName();
@JsonProperty("scoredate")
/* @JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)*/
@JdbiOptions(columnName = "scoredate")
@Nullable
LocalDate scoreDate();
}
我在配置JDBI连接时为LocalDate
数据类型设置了映射器。
public static void configureDbi(DBI dbi) {
// Register argument factories
dbi.registerArgumentFactory(new NullDoubleArgumentFactory());
dbi.registerArgumentFactory(new UuidArgumentFactory());
dbi.registerArgumentFactory(new LocalDateArgumentFactory());
dbi.registerArgumentFactory(new InstantArgumentFactory(Optional.of(TimeZone.getTimeZone("UTC"))));
dbi.registerColumnMapper(new InstantMapper(Optional.of(TimeZone.getTimeZone("UTC"))));
dbi.registerArgumentFactory(new OptionalArgumentFactory("com.microsoft.sqlserver.jdbc.SQLServerDriver"));
dbi.registerArgumentFactory(new OptionalIntArgumentFactory());
dbi.registerArgumentFactory(new OptionalDoubleArgumentFactory());
// Register column mappers
dbi.registerColumnMapper(new UuidColumnMapper());
dbi.registerColumnMapper(new LocalDateMapper());
}
答案 0 :(得分:0)
我也遇到了他的问题并发现Dropwizard LocalDateArgumentFactory类确定是否创建Argument类来处理值的方式是使用instanceof check:
public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
return value instanceof LocalDate;
}
由于value为null,因此返回false,我通过创建它解决了这个问题:
public class NullAwareLocalDateArgumentFactory extends LocalDateArgumentFactory {
@Override
public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
if(value == null){
//Look at the expected type. Tbh. not sure why it isn't simply doing this by default ...
return LocalDate.class.isAssignableFrom(expectedType);
}
else {
return super.accepts(expectedType, value, ctx);
}
}
}