web-dev-qa-db-fra.com

Java 8 LocalDate in hibernate mal mappé sur TIMESTAMP

J'utilise Spring Boot 1.4.2, qui apporte hibernate 5.0.11 (JPA 2.1). Je souhaite utiliser les classes de temps Java 8 dans mes entités, et ainsi inclure hibernate-Java8.

Mon entité définit un champ LocalDate.

@Entity
@Table(name = "my_alarms_timeline", indexes = {...})
public class MyAlarm {
    ...
    @Column(name = "validity_date")
    @NotNull
    private LocalDate validityDate;
}

Je pense que cela sera mis en correspondance avec une date dans ma base de données H2.

Dans ma base de données, je déclare ceci comme validity_date DATE NOT NULL,.

Lorsque j'essaie d'exécuter des tests, l'erreur suivante apparaît: [INFO] Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [validity_date] in table [my_alarms_timeline]; found [date (Types#DATE)], but expecting [timestamp (Types#TIMESTAMP)]

À ma grande surprise, si je modifie la définition de la base de données en validity_date TIMESTAMP NOT NULL,, le message d'erreur s'affiche.

Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [validity_date] in table [my_alarms_timeline]; found [timestamp (Types#TIMESTAMP)], but expecting [date (Types#DATE)]

Ceci est juste le message inverse du précédent.

J'ai également essayé, au lieu d'inclure hibernate-Java8, d'utiliser un AttributeConverter<LocalDate, Java.sql.Date> mais cela produit le même résultat d'erreur.

Que dois-je faire pour que mon LocalDate soit correctement mappé sur une date dans la base de données?

J'ai également essayé avec un champ LocalDateTime mappé sur un TIMESTAMP, et cela fonctionne sans problème ...

6
Philipp

Je l’ai donc fait fonctionner en ajoutant un columnDefinition="DATE" à la @Columnannotation.

@Entity
@Table(name = "my_alarms_timeline", indexes = {...})
public class MyAlarm {
    ...
    @Column(name = "validity_date", columnDefinition = "DATE")
    @NotNull
    private LocalDate validityDate;
}

Vous ne savez pas pourquoi personne d'autre ne voit ce problème ...

12
Philipp

Je ne l'ai pas utilisé au printemps, mais dans JPA "standard", j'ai fait quelque chose comme:

@Converter(autoApply = true)
public class OffsetDateTimeAttributeConverter implements AttributeConverter<OffsetDateTime, Timestamp> {
    @Override
    public Timestamp convertToDatabaseColumn(OffsetDateTime entityValue) {
        if( entityValue == null )
            return null;

        return Timestamp.from(Instant.from(entityValue));
    }

    @Override
    public OffsetDateTime convertToEntityAttribute(Timestamp databaseValue) {
        if( databaseValue == null )
            return null;

        return OffsetDateTime.parse(databaseValue.toInstant().toString());
    }
}

Ma table a des colonnes "timestamp with timezone". Mon @Entity utilise ensuite OffsetDateTime. Vous devriez être capable de convertir vos types de données avec quelque chose comme ça.

4
stdunbar

Je soupçonne que vous avez le code suivant quelque part dans votre projet:

@EntityScan(basePackageClasses = { Application.class, Jsr310JpaConverters.class })

Si vous utilisez Hibernate 5.x, supprimez la référence à Jsr310JpaConverters.class, sinon Hibernate et Spring essaieront de gérer les objets Date et heure Java 8. Cela peut entraîner un comportement très inconstant (par exemple, des instances de LocalDate persistantes avec une valeur incorrecte lors de l'exécution sur des machines n'utilisant pas l'UTC).

Vous devez également supprimer toutes les occurrences de:

@Column(columnDefinition = "DATE")

Si vous en avez besoin, cela indique que quelque chose ne va pas avec votre configuration de veille prolongée.

2