Question

Dans ma base de données SQL Server 2000, j'ai une colonne d'horodatage (dans la fonction non dans le type de données) de type DATETIME nommée lastTouched définie sur getdate () comme valeur par défaut / binding.

J'utilise les classes d'entités JPA générées par Netbeans 6.5 et je les ai dans mon code

@Basic(optional = false)
@Column(name = "LastTouched")
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;

Cependant, lorsque j'essaie de placer l'objet dans la base de données, 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 définir @Basic sur (facultatif = true) , mais une exception est générée, indiquant que la base de données n'autorise pas null valeurs de la colonne TIMESTAMP , ce qui n'est pas le cas.

ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.

Je l’avais précédemment utilisé dans Hibernate pur, mais j’ai eu l’impression de passer à JPA et je ne sais pas 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 Hibernate comme couche de persistance JPA.

Était-ce utile?

La solution

J'ai résolu le problème en modifiant le code en

@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;

La colonne timestamp est donc ignorée lors de la génération des insertions SQL. Je ne sais pas si c'est la meilleure façon de s'y prendre. Vos commentaires sont les bienvenus.

Autres conseils

Je réalise que c'est un peu tard, mais j'ai réussi à annoter une colonne d'horodatage avec

@Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

Ceci devrait également fonctionner avec CURRENT_DATE et CURRENT_TIME . J'utilise JPA / Hibernate avec Oracle, donc YMMV.

@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;

cela a fonctionné pour moi. plus d'informations

Cela fonctionne bien avec JPA2.0 et MySQL 5.5.10, dans les cas où je ne me soucie que de la dernière fois que la ligne a été modifiée. MySQL créera un horodatage lors de la première insertion et à chaque appel de UPDATE sur la ligne. (NOTE: cela posera un problème si je voulais savoir si UPDATE avait réellement apporté une modification).

Le " horodatage " la colonne dans cet exemple est comme un "& dernier; touché" " column.x`

Le code ci-dessous utilise une colonne distincte " version " pour un verrouillage optimiste.

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;
}

(REMARQUE: @Version ne fonctionne pas sur une colonne "DATETIME" MySQL, où le type d'attribut est "Date" dans la classe Entity. C'était parce que Date générait une valeur allant jusqu'à la milliseconde, mais MySQL ne stockait pas la milliseconde. Ainsi, lorsqu’il a comparé le contenu de la base de données avec l’entité "liée", il pensait que leurs numéros de version étaient différents.

Du manuel de MySQL concernant 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 chaque base de données possède des horodatages de mise à jour automatique (par exemple, Postgres). J'ai donc décidé de mettre à jour ce champ manuellement partout dans mon code. Cela fonctionnera avec toutes les bases de données:

thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);

Il existe des raisons d'utiliser des déclencheurs, mais pour la plupart des projets, ce n'est pas l'un d'entre eux. Les déclencheurs vous plongent encore plus profondément 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 tolérant, ne nécessitant rien de plus que

@Column(name="LastTouched")

MySQL 5.7 .9 (CentOS 6, OpenJDK 64 bits 1.8.0_72) fonctionne uniquement 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)

  • hibernate-entitymanager 5.0.2
  • hibernate-validator 5.2.2
  • mysql-connector-java 5.1.38
@Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
@Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top