14

I have an entity:

@Entity
@EntityListeners(MyEntityListener.class)
class MyEntity{ ... }

And the listener:

class MyEntityListener{
    @PrePersist
    @PreUpdate
    public void doSomething(Object entity){ ... }
}

I'm using the Spring Data generated DAO for this entity (1.4.1) and EclipseLink. The code behavior is as follows:

MyEntity entity = new Entity();
entity = dao.save(entity); // the doSomething() is called here
// change something it the entity and save it again
dao.save(entity); // the doSomething() is NOT called here, checked with breakpoint

The problem has already been described by someone in 2009, however, they did not came up with any solution. I wonder if anyone has and idea how to solve it?

Sylvain Bugat
  • 7,704
  • 3
  • 29
  • 30
fracz
  • 20,536
  • 18
  • 103
  • 149
  • Are you sure that `doSomething()` is not called at all for the second time? It may be called prior to transaction commit, not immediately. – axtavt Nov 07 '13 at 17:48
  • Have you tried to detach the entity before the second save()? – V G Nov 07 '13 at 17:49
  • @AndreiI you are right, when I get the entity by `entity = dao.findOne(entity.getId())` before saving it the second time, listener's method is called successfully. Please post it as an answer, and the reason if you know what's going on. – fracz Nov 07 '13 at 18:03
  • I'm using `JpaRepository`, calling `repository.saveAndFlush(entity)` did fire `@PreUpdate` callback. Hope this helps. – maximus Jun 23 '22 at 16:58

2 Answers2

11

As you said, the callback method is called the second time, if the entity is detached or fetched again from DB.

I cannot explain it exactly, but can think of the scenario described here, when no dirty fields are identified before the second save() call and thus the @PreUpdate callback not called. Or it may be simply a bug within your version of EclipseLink.


UPDATE

In the JPA 2.0 specification I found the following, which is exactly your behaviour (3.5.2 Semantics of the Life Cycle Callback Methods for Entities):

Note that it is implementation-dependent as to whether PreUpdate and PostUpdate call- backs occur when an entity is persisted and subsequently modified in a single transaction or when an entity is modified and subsequently removed within a single transaction. Portable applications should not rely on such behavior.

Community
  • 1
  • 1
V G
  • 18,822
  • 6
  • 51
  • 89
2

what is your transactional setting around your two different save()?

I think there would be some differnce between save()/update()/merge()/persist(), for the different status of an entity(transient, persistent, detached), the operations is not the same as you thought and your annotation @PrePersist and @PreUpdate did not take effect.

Terry Zhao
  • 115
  • 7
  • I have Spring's transaction management turned on, but the flushing seems not to be a problem because when I replace both `save` calls with `saveAndFlush` there is no difference. – fracz Nov 07 '13 at 17:47
  • after your first save, the entity is still in persistent status. maybe saveOrUpdate() can resovle your problem. – Terry Zhao Nov 07 '13 at 17:50
  • 1
    `saveOrUpdate()` in neither in the `JpaRepository` nor in the `CrudRepository` interfaces. – fracz Nov 07 '13 at 17:54
  • Is there a way to detach the pesistent entity before you do a second save? – Terry Zhao Nov 07 '13 at 18:02
  • I'm not sure this link works for your case http://stackoverflow.com/questions/13588565/spring-data-jpa-why-are-changes-to-a-returned-entity-automatically-persisted is there a method EntityManager.detach()? – Terry Zhao Nov 07 '13 at 18:07
  • Fetching the entity again from database before saving it the second time solves the problem. See my comment above to Andreil. – fracz Nov 07 '13 at 18:11