Définir une colonne de timestamp JPA à générer par la base de données?
dans ma base de données SQL Server 2000, j'ai une colonne timestamp (in function not in data type) de type DATETIME
lastTouched
getdate()
comme valeur par défaut/de liaison.
j'utilise les classes d'entités JPA générées par Netbeans 6.5, et j'ai ceci dans mon code
@Basic(optional = false)
@Column(name = "LastTouched")
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
Cependant lorsque j'essaie de mettre l'objet dans la base de données que je reçois,
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched
j'ai essayé de configurer le @Basic
(optional = true)
, mais cela jette une exception disant le la base de données ne permet pas de null
valeurs TIMESTAMP
colonne, ce qui n'est pas prévu.
ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.
j'ai déjà obtenu que cela fonctionne en hibernation pure, mais j'ai le sens commuté à JPA et je n'ai aucune idée comment lui dire que cette colonne est supposée être générée du côté de la base de données. Notez que J'utilise toujours hibernation comme couche de persistance JPA.
5 réponses
j'ai résolu le problème en changeant le code
@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
ainsi la colonne timestamp est ignorée lors de la génération des inserts SQL. Vous ne savez pas si c'est la meilleure façon d'aller à ce sujet. Commentaires sont les bienvenus.
je me rends compte que c'est un peu tard, mais j'ai réussi à annoter une colonne timestamp avec
@Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
cela devrait aussi fonctionner avec CURRENT_DATE
et CURRENT_TIME
. J'utilise JPA/hibernation avec Oracle, donc YMMV.
j'ai ce travail bien à l'aide de JPA2.0 et MySQL 5.5.10, pour les cas où je ne se soucient que la dernière fois que la ligne a été modifiée. MySQL va créer un timestamp sur la première insertion, et chaque mise à jour est appelée sur la ligne. (NOTE: ce sera problématique si je me souciais de savoir si oui ou non la mise à jour a réellement fait un changement).
la colonne" timestamp "dans cet exemple est comme une colonne" last-touched".x'
le code ci-dessous utilise une colonne séparée "version" pour optimiste verrouillage.
private long version;
private Date timeStamp
@Version
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
// columnDefinition could simply be = "TIMESTAMP", as the other settings are the MySQL default
@Column(name="timeStamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
@Temporal(TemporalType.TIMESTAMP)
public Date getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Date timeStamp) {
this.timeStamp = timeStamp;
}
(NOTE: @Version ne fonctionne pas sur une colonne MySQL "DATETIME", où l'attribut type est "Date" dans la classe Entity. C'était parce que Date générait une valeur jusqu'à la milliseconde, cependant MySQL ne stockait pas la milliseconde, donc quand il a fait une comparaison entre ce qui était dans la base de données, et l'entité "attachée", il pensait qu'ils avaient des numéros de version différents)
From the MySQL manual regarding TIMESTAMP :
With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
Je ne pense pas que toutes les bases de données ont des horodateurs de mise à jour automatique (par exemple Postgres). J'ai donc décidé de mettre à jour ce champ manuellement partout dans mon code. Cela fonctionne avec toutes les bases de données:
thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);
il y a des raisons d'utiliser des déclencheurs, mais pour la plupart des projets, ce n'en est pas une. Les déclencheurs vous creusent encore plus dans une implémentation de base de données spécifique.
MySQL 5.6.28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) semble être très indulgent, pas exiger quelque chose au-delà
@Column(name="LastTouched")
MySQL 5.7.9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) ne fonctionne qu'avec
@Column(name="LastTouched", insertable=false, updatable=false)
pas:
FAILED: removing @Temporal
FAILED: @Column(name="LastTouched", nullable=true)
FAILED: @Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
mes autres informations système (identiques dans les deux environnements)
- hibernation-entitymanager 5.0.2
- hibernate-validator 5.2.2
- mysql-connector-java 5.1.38
@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;
cela a fonctionné pour moi. plus d'info