3

I'm using PreInsert and PreUpdate EventListeners in Hibernate to set the value of "created" and "updated" timestamps prior to writing my entity to the database. The problem is the next time Hibernate reads then flushes the entity Hibernate sees the changed timestamps and thinks the object needs to be updated even if nothing else changed. So the listeners are fired again, an update occurs, and the same over and over.

Ideally I'd like to be able to assign these timestamps without Hibernate thinking the object is dirty the next time it is flushed. What is the best solution for handling this? I assume I could override the dirty check, but I wanted to see what others do.

Here's some example code for reference (This is just sample code so no need to nitpick):

@Entity
class MyEntity {
    @Id
    Long id = Long.valueOf(1);
    @Temporal(TemporalType.TIMESTAMP)
    private Date created;
    @Temporal(TemporalType.TIMESTAMP)
    private Date updated;

    @Override
    public void setCreated(Date created) {
        this.created = created;
    }

    @Override
    public void setUpdated(Date updated) {
        this.updated = updated;
    }
}

public class PreInsertAndUpdateEventListener implements PreInsertEventListener, PreUpdateEventListener {
    @Override
    public boolean onPreUpdate(PreUpdateEvent event) {
        MyEntity.class.cast(event.getEntity()).setUpdated(new Date());
        return false;
    }

    @Override
    public boolean onPreInsert(PreInsertEvent event) {
        MyEntity.class.cast(event.getEntity()).setCreated(new Date());
        return false;
    }
}

public void updatedTest() {
    Session session = sessionFactory.openSession();
    Transaction t = session.beginTransaction();

    MyEntity p = new MyEntity();
    Serializable id = session.save(p);
    session.flush();

    for (int i = 0; i < 5; i++) {
        p = (MyEntity) session.get(MyEntity.class, id);
        session.update(p);
        session.flush(); // Update always fires here
    }

    t.commit();
    session.close();
}
Josh
  • 875
  • 1
  • 13
  • 25
  • http://stackoverflow.com/questions/221611/creation-timestamp-and-last-update-timestamp-with-hibernate-and-mysql do it like here and the events shouldn't get called. – dzezzz Jun 13 '16 at 12:52

1 Answers1

2

The solution I decided to take was to update Hibernate's state to match that of the entity each time I modify the entity via an event listener. The implementation looks something like this:

StandardProperty[] properties = event.getPersister().getEntityMetamodel().getProperties();
Object[] state = event.getState();

for (int i = 0; i < properties.length; i++) {
    if (properties[i].getName().equals("updated")) {
        state[i] = timestamp;
        break;
    }
}
Josh
  • 875
  • 1
  • 13
  • 25