0

I have one JPA entity that has a created date and a modified date column. On creation/persist, both the created date and modified date are generated by the default value given in the database, which is a timestamp. The creation works, however, when I try to do an update/merge, I cannot figure out how to change the modified date by using the default value in the database. Any advice? This is the current setup:

....
@Temporal(TemporalType.DATE)
@Column(name="CREATED_DATE", insertable = false, updatable = false)
private Date createdDate;

@Temporal(TemporalType.DATE)
@Column(name="MODIFIED_DATE", insertable = false)
private Date modifiedDate;
....

-

public Database changeDate(Database oldValues)
    Database newvalues = new Database();
    ....
    newValues.setCreatedDate(oldValues.getCreatedDate);
    //newValues.setModifiedDate(); <-- (Should use the default value in the database)
    ....
    em.merge(newValues); <-- (EntityManager)
    em.getTransaction().commit();

** Just in case I didn't make myself clear, I just don't know how to make it update with the default value set in the database.

Racco Taco
  • 15
  • 7
  • Just to make this a bit clearer, are you saying "I am trying to update newValues.modifiedDate to a new Date() value, but after transaction commit, the DB shows no update" or "I am trying to update newValues.modifiedDate to a null value, but I am getting an exception"? – Will Dazey Feb 22 '17 at 21:52
  • I wanted to try to make it update to the default value it has stored in the database. Setting it to null didn't help. I may do the new Date() route, but I would still prefer the default value. – Racco Taco Feb 22 '17 at 21:54
  • I would suggest editing your question and removing "null". If you reword your question to explain precisely what you are trying to do, it will be much easier for us to assist. – Will Dazey Feb 22 '17 at 21:56
  • Edited the question. Hopefully it's clearer now. – Racco Taco Feb 22 '17 at 22:00
  • `newValues` is a `new Database()` entity, yes? So `em.merge(newValues)` is not what you should be doing with it. It needs to be persisted. IOW: `em.persist(newValues)` – Will Dazey Feb 22 '17 at 22:14
  • `em.merge()` should be used to reattach a detached entity that is not being managed by the persistence context. But if the entity is brand new, you should be persisting it. – Will Dazey Feb 22 '17 at 22:16
  • I believe what you are stating is the database is setting the value for you when an insert statement is issued. You should just need JPA to pull the value into your entity. This isn't covered by JPA but is by some providers https://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/a_returninsert.htm – Chris Feb 22 '17 at 23:26
  • @WillDazey - I thought I couldn't persist since the unique ID is already in use? I will try that momentarily. – Racco Taco Feb 23 '17 at 13:33
  • Ok, I suppose in your example you didn't show how you set the @Id field. If the id value already exists, then you can not persist() the new until you remove() the old. – Will Dazey Feb 23 '17 at 15:17

3 Answers3

1

you want to set Null value to date. please add nullable property in your date annotation. it will work.

add it in your annotation nullable = true

@Temporal(TemporalType.DATE)
@Column(name="CREATED_DATE",nullable = true, insertable = false, updatable = false)
private Date createdDate;

@Temporal(TemporalType.DATE)
@Column(name="MODIFIED_DATE", nullable = true, insertable = false)
private Date modifiedDate;
Kumaresan Perumal
  • 1,926
  • 2
  • 29
  • 35
  • In the database, I have it set to where modified date cannot be a null value. With the annotation, it just gives me the same error. - that the value cannot be set to null. I don't think I made that clear in my question. Sorry about that :c – Racco Taco Feb 22 '17 at 21:42
0

If I understand the question correctly, you want to make sure that the MODIFIED_DATE column always gets set to the CURRENT_TIMESTAMP. Then, when a Database entity gets updated and it's other fields modified, the MODIFIED_DATE column will be set to the CURRENT_TIMESTAMP.

I assume that your DB table looks something like this:

CREATE TABLE Database (
    ID int NOT NULL,
    CREATED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    MODIFIED_DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)

What you want to do is add a @PreUpdate method to your Database entity class and have it set the modifiedDate attribute to a new Date() each time. Then, whenever an update is made to the entity, the MODIFIED_DATE column will be set to a new date!

Here is an example:

@PreUpdate
protected void onUpdate() {
    modifiedDate = new Date();
}

Try a simple example and see how it works:

em.getTransaction().begin();
Database db = new Database(1, "First Value");
em.persist(db);
em.getTransaction().commit();

em.getTransaction().begin();
Database db2 = em.find(Database.class, 1);
db2.setValue("New Value!");
em.getTransaction().commit();
Will Dazey
  • 253
  • 2
  • 13
  • so basically using the new Date() route - it seems to be my only option so far. The PreUpdate is a pretty nice feature, didn't know it existed. – Racco Taco Feb 23 '17 at 13:49
  • @RaccoTaco The issue is that using the Default functionality of your DB table is only for inserting NEW rows. If you insert a new row and fail to supply a value for a column with a default, the default value is used to keep the value from being NULL. In your usecase, after the value is initialized to the default, it cannot be undone without deleting the row and re-inserting it. – Will Dazey Feb 23 '17 at 15:07
  • While this may work, I warn against it. In general, I believe it to be a poor design decision to put this business logic on the DB. Also, my answer offers more flexibility for managing your value. Relying on the provider or the DB to set the value means that changing the value manually is either impossible or difficult – Will Dazey Feb 23 '17 at 15:12
0

There is an annotation you could use javax.persistence.Version

@Column(name="CREATED_DATE", updatable = false)
private java.sql.Timestamp createdDate = new java.sql.Timestamp(System.currentTimeMillis());

@Version
@Column(name="MODIFIED_DATE")
private java.sql.Timestamp modifiedDate;

Both fields need only have a getter, no setter. The JPA will compare and update the timestamp value on it's own. Otherwise if you rely on the database to generate it for you, you might as well try @GeneratedValue(strategy = GenerationType.IDENTITY) or AUTO, but I'm pretty sure that won't work in Hibernate. Maybe it will work in other JPA providers. In Hibernate, the AUTO is value always falls-back to SEQUENCE, so no chance of that strategy working.

coladict
  • 4,799
  • 1
  • 16
  • 27
  • This one was really close - the only issue was that the GeneratedValue annotation is already being used for the ID, and apparently you can only have one per entity (maybe I should have said that form the start, but I thought it wouldn't be a big deal). And the type Date isn't allowed for version. I tried using Timestamp just to see if it would work, but then the entity couldn't be matched with the database. – Racco Taco Feb 23 '17 at 13:48
  • If you truncate the microseconds (anything smaller than milliseconds, really) from the values in the database, `@Version` with Timestamp should work. That's what we had to do, before we moved to Java 8 and switched to `Instant`. – coladict Feb 23 '17 at 14:37