kboom
kboom

Reputation: 2339

JPA @PreUpdate is not called

Could someone explain to me the reason of the following behavior?

EntityA is being first created and then persisted using em.persist(..) method. @PrePersist callback is executed before the transaction ends. It works fine.

In the new transaction EntityA is obtained using em query. Then, some operations modifying its persistable fields are executed and this transaction ends. But on em.flush(), the @PreUpdate method is never called nor is @PrePersist (the latter I anticipated). Why?

// EDIT

That's the trace just before failure. "Done materializing entity" is the effect of the first operation in the transaction that fails.

DEBUG: org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [com.example.entity#1]
DEBUG: org.hibernate.event.internal.AbstractFlushingEventListener - Processing flush-time cascades
DEBUG: org.hibernate.ejb.AbstractEntityManagerImpl - Mark transaction for rollback
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction rollback
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl@341a736]
DEBUG: org.hibernate.engine.transaction.spi.AbstractTransactionImpl - rolling back
DEBUG: org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - rolled JDBC Connection

Thanks!

Upvotes: 4

Views: 17745

Answers (2)

Anand Rockzz
Anand Rockzz

Reputation: 6658

In my case @Transactional & @Modifying were missing in Service layer update method.

Upvotes: 0

cmd
cmd

Reputation: 11841

In the new transaction, @PrePersist would be called if you performed a merge to update EntityA's state. Simply modifying EntityA's persistent fields without a merge will not result in a call to @PrePersist

It is similar for @PreUpdate, however is not guaranteed that the PreUpdate callback is invoked when an entity is persisted and then modified in a single transaction (which is not the case in your example).

If you are using a transaction-scoped container-managed entity manager, then when a transaction ends, those entities become detached. This is likely what is happening when your first transaction completes. These detached entities will continue to live outside of the persistence context in which they were persisted, however the state of those entities are no longer guaranteed to be synchronized with the database. To ensure their state is synchronized, you should perform a merge in your second transaction. This will cause the resulting entity to be managed by the persistence context and thus able to be synchronized with the database.

If you don't like this behavior you can choose to use an extended persistence context.

Upvotes: 5

Related Questions