I\'m trying to leverage EntityListener objects and callback methods within my Seam/Hibernate/JPA application. I\'m using a Seam 2.2-managed persistence context on JBoss 5.1
Without the actual tests you've ran, the way you've ran them and the output you've got (from your listener) it is hard to say anything clever, however using MySQL with the following table and data
CREATE TABLE `test` (
`id` int(11)
`data` char(1),
PRIMARY KEY (`id`)
);
+----+------+
| id | data |
+----+------+
| 1 | a |
+----+------+
I've ran this test
EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
// persisting new item
Test b = new Test();
b.id = 2;
b.data = 'b';
tx.begin();
em.persist(b);
tx.commit();
// update existing item
b.data = 'a';
tx.begin();
em.merge(b);
tx.commit();
// load existing
Test a = em.find(Test.class, 1);
// remove existing
tx.begin();
em.remove(b);
tx.commit();
em.close();
emf.close();
and got the following output
prePersist(2: b)
postPersist(2: b)
preUpdate(2: a)
postUpdate(2: a)
postLoad(1: a)
preRemove(2: a)
postRemove(2: a)
(I've implemented toString()
in Test
so it emits id + ": " + data
and I've reduced the logging statements in my listener class to System.out.format("preXxx(%s)\n", e)
so that it would be read better.)
Please see if this works for you in your environment for starters, so that we could narrow down the problem, but at least post some of your input/output.
I've tried to boot up a simple JBoss/Seam test application for myself to run a test, however I don't get Seam … at all. Anyway, I took a look at your examples and here's what I think your problem is.
I assume that your runTest()
method starts a managed persistence session or something like that, so before the method gets called entityManager.getTransaction().begin()
is called by Seam, and when the method exists entityManager.getTransaction().commit()
is called. Here's my opinion on what seems to happen in your scenario.
// transaction begin
// persist - @PrePersist called
this.entityManager.persist(e);
// flush - @PostPersist should be called
this.entityManager.flush();
// clear - the context is cleared
this.entityManager.clear();
// transaction end
I've tested this scenario, however using MySQL with manual persistence management @PostPersist
is called.
I've tried setting entityManager.setFlushMode(...)
to FlushModeType.AUTO
and FlushModeType.COMMIT
but it changes nothing. However in the Seam documentation there is a third enum, FlushModeType.MANUAL, which isn't in the JPA specification and is Seam specific. It should be fed to the @Begin annotation (this annotation probably indicates that the annotated method starts the transaction at hand).
I'm quite certain that in your case flush()
commits nothing to the database until the transaction is over (the methods runs out). If you remove the call to the clear()
method @PostPersist
should be called.
This seems just fine to me!
I assume your problem is that @PrePersist
and @PostPersist
doesn't get called at all, but you call persist()
. Because you use find()
the returned instances will already be managed. Calling persist()
on them does nothing. However mutating their state and calling flush()
triggers @PreUpdate
. @PostUpdate
doesn't get called of the exact same reason @PostPersist
didn't get called in the first test: you clear the persistence context before anything could propagate to the database.
Your problem comes down to the fact that you clear()
your persistence context before anything gets committed to the database.
I suggest you to make some really simple tests and try playing with the FlushModeType
settings I mentioned. Update your Hibernate version. I use the latest version from 3.x.x series (3.8.6.Final). By the way, you didn't exactly share your Hibernate version with us, but it could matter a lot!