2009-05-01 27 views
43

En mi base de datos de SQL Server 2000, tengo una columna de marca de tiempo (en la función no en el tipo de datos) del tipo DATETIME denominada lastTouched establecida en getdate() como valor/enlace predeterminado.¿Configura una columna de marca de tiempo JPA para ser generada por la base de datos?

estoy usando el Netbeans 6.5 generados clases de entidad JPA, y tienen esto en mi código

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

Sin embargo, cuando intento poner el objeto en la base de datos que recibo,

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched 

I He intentado configurar la configuración de @Basic a (optional = true), pero eso arroja una excepción diciendo que la base de datos no permite null valores para la columna TIMESTAMP, que no tiene por diseño.

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

previamente Tengo que esto funcione en Hibernate pura, pero he sentido cambiado a JPA y no tienen idea de cómo decirle que esta columna se supone que debe ser generada en el lado de la base de datos. Tenga en cuenta que todavía estoy usando Hibernate como mi capa de persistencia JPA.

Respuesta

42

He arreglado el problema cambiando el código para

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

Así la columna de marca de tiempo se ignora cuando se genera inserciones SQL. No estoy seguro de si esta es la mejor manera de hacerlo. Comentarios son bienvenidos.

+5

También es posible que desee agregar @Column (name = "LastTouched", insertable = false, actualizable = false) de usar la base de datos genera marcas de tiempo también con las instrucciones UPDATE de SQL. –

+0

Gracias Juha. Estoy seguro de que eso me habría echado a perder más adelante en el camino. –

+0

En realidad, al pensarlo más, creo que necesitaré la columna de actualización, ya que voy a necesitar actualizarla a través de Java cuando realice cambios en la columna. A menos que haya una manera de hacer la actualización de la columna en el lado de la base de datos de alguna manera. –

27

me di cuenta que es un poco tarde, pero he tenido éxito con la anotación de 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, entonces YMMV.

+5

¡Esto funcionó para nosotros! Lo combinamos con 'insertable = false, updatable = false' –

+0

' ERROR 4371 --- [main] org.hibernate.tool.hbm2ddl.SchemaExport: Tiene un error en su sintaxis SQL; revise el manual que corresponde a su versión del servidor MySQL para la sintaxis correcta para usar cerca de '' TIMESTAMP DEFAULT CURRENT_TIMESTAMP' no nulo, 'full_content' longtext not null 'en la línea 1'. Mi columna es: '@Column (nullable = false, name =" created_at ", updatable = false, columnDefinition =" TIMESTAMP DEFAULT CURRENT_TIMESTAMP ")' y 'private Timestamp createdAt;' –

3

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 llame a UPDATE en la fila. (NOTA: esto será problemático si me importa si la ACTUALIZACIÓN realmente hizo un cambio).

La columna "marca de tiempo" en este ejemplo es como un "último tocado" column.x`

El código siguiente se utiliza una columna de "versión" separado 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 de MySQL "fecha y hora", en el que el tipo de atributo es "fecha" en la clase de entidad Esto se debió a la fecha estaba generando un valor hasta la milésima de segundo, sin embargo MySQL no estaba almacenando la milésima de segundo, por lo que cuando se hizo una comparación entre lo que estaba en la base de datos, y la entidad "unida", que pensaban que tenían diferentes números de versión)

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. 
0

I tener esto funcionando bien usando JPA 2.0 y MyS QL 5.5.10.

que inserta un campo Timesamp así:

@Column(name = "LastTouched") 
private Timestamp lastTouched; 
2

no creo que cada base de datos tiene las marcas de tiempo de actualización automática (por ejemplo Postgres). Así que decidí actualizar este campo de forma manual en todas partes de mi código. Esto funcionará con cada base de datos:

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

Hay razones para utilizar disparadores, pero para la mayoría de los proyectos, esto no es una de ellas. Los disparadores lo excavan aún más en una implementación de base de datos específica.

MySQL 5.6 0,28 (Ubuntu 15.10, OpenJDK 64 bits 1.8.0_66) parece ser muy indulgente, que no requiere nada más allá de

@Column(name="LastTouched") 

MySQL 5.7 0,9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) sólo 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éntico en ambos ambientes)

  • hibernación-EntityManager 5.0.2
  • hibernación-validador 5.2.2
  • mysql-connector-java 5.1.38
+0

Información muy útil, gracias - Me imagino mucho la gente será mordida por esta actualización a MySQL 5.7.x – James

+0

@James - gracias, pero acabo de enumerar las diferencias que conocía. No sé con certeza cuál es la diferencia crítica. Podría ser algo completamente diferente. Con suerte, alguien más puede basarse en esta respuesta. – GlenPeterson

+1

Sí, lo siento, debería haber agregado que encontré este error después de actualizar de MySQL 5.6 a 5.7 en Ubuntu 14.04.1 (OS y JDK no fueron cambiados AFAIK). Así que asumí que la versión de MySQL era el factor crítico aquí. – James

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

esto funcionó para mí. more info

Cuestiones relacionadas