¿Establecer una columna de marca de tiempo JPA para que la base de datos la genere?
-
03-07-2019 - |
Pregunta
En mi base de datos SQL Server 2000, tengo una columna de marca de tiempo (en función no en el tipo de datos) del tipo DATETIME
llamado lastTouched
establecido en getdate ()
como su valor / enlace predeterminado.
Estoy usando las clases de entidad JPA generadas por Netbeans 6.5, y tengo esto en mi código
@Basic(optional = false)
@Column(name = "LastTouched")
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
Sin embargo, cuando trato de poner el objeto en la base de datos que obtengo,
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched
He intentado configurar @Basic
en (opcional = true)
, pero eso arroja una excepción que dice que la base de datos no permite nulo
valores para la columna TIMESTAMP
, que no lo hace por diseño.
ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.
Anteriormente conseguí que esto funcionara en Hibernate puro, pero tengo sentido cambiar a JPA y no tengo idea de cómo decirle que se supone que esta columna se generará en el lado de la base de datos. Tenga en cuenta que todavía estoy usando Hibernate como mi capa de persistencia JPA.
Solución
Solucioné el problema cambiando el código a
@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
Por lo tanto, la columna de marca de tiempo se ignora al generar inserciones SQL. No estoy seguro si esta es la mejor manera de hacerlo. Los comentarios son bienvenidos.
Otros consejos
Me doy cuenta de que esto es un poco tarde, pero he tenido éxito al anotar una columna de marca de tiempo con
@Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
Esto también debería funcionar con CURRENT_DATE
y CURRENT_TIME
. Estoy usando JPA / Hibernate con Oracle, así que YMMV.
@Column(nullable = false, updatable = false)
@CreationTimestamp
private Date created_at;
esto funcionó para mí. más información
Tengo esto funcionando bien usando JPA2.0 y MySQL 5.5.10, para los casos en que solo me importa la última vez que se modificó la fila. MySQL creará una marca de tiempo en la primera inserción, y cada vez que se llama a UPDATE en la fila. (NOTA: esto será problemático si me preocupa si la ACTUALIZACIÓN realmente hizo un cambio).
La " marca de tiempo " la columna en este ejemplo es como un " último tocado " column.x`
El código siguiente utiliza una columna separada " versión " para el bloqueo optimista.
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;
}
(NOTA: @Version no funciona en una columna MySQL " DATETIME " donde el tipo de atributo es " Fecha " en la clase Entidad. Esto se debía a que Date estaba generando un valor hasta el milisegundo, sin embargo, MySQL no almacenaba el milisegundo, así que cuando hizo una comparación entre lo que estaba en la base de datos y la entidad adjunta, pensó que tenían diferentes números de versión)
Del manual de MySQL relacionado con TIMESTAMP :
With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
No creo que todas las bases de datos tengan marcas de tiempo de actualización automática (por ejemplo, Postgres). Así que he decidido actualizar este campo manualmente en todas partes en mi código. Esto funcionará con cada base de datos:
thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);
Hay razones para usar desencadenadores, pero para la mayoría de los proyectos, este no es uno de ellos. Los desencadenadores le permiten profundizar en una implementación de base de datos específica.
MySQL 5.6 .28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) parece ser muy indulgente, no requiere nada más allá de
@Column(name="LastTouched")
MySQL 5.7 .9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) solo funciona con
@Column(name="LastTouched", insertable=false, updatable=false)
no:
FAILED: removing @Temporal
FAILED: @Column(name="LastTouched", nullable=true)
FAILED: @Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
Mi otra información del sistema (idéntica en ambos entornos)
- 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`