0

我目前正在使用 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();  
}

LocalDate在配置我的 JDBI 连接时,我为数据类型设置了映射器。

 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());
    }
4

1 回答 1

0

我也遇到了他的问题,发现 Dropwizard LocalDateArgumentFactory 类确定是否创建 Argument 类来处理值的方式是使用 instanceof 检查:

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);
        }
    }
}
于 2017-10-16T09:18:23.733 回答