Actually EntityManager.persist is the same as
DataContext.registerObject. It does not commit to DB until "flush" is
called or external transaction is committed. But the rest of the
analysis is correct. So I am +1 on the following, even though there
we'll end up with mismatch against JPA (Cayenne.postRegister ==
JPA.prePersist; Cayenne.prePersist != JPA.prePersist) :
postRegister <- called when a non-persisted object is registered
with a data context. You could even have a preRegister, but that's
probably overkill.
prePersist <- just before DB insert
postPersist <- just after DB insert
preUpdate < - just before DB update of existing object
postUpdate <- just after DB update
postLoad <- just after a committed obj. is fetched from the DB.
Now wonder what we should do with "remove":
preRemove <- just before DB delete
postRemove <-just after DB delete
There are 3 similar lifecycle points: (1) after object is deleted in
context, (2) before deleted object is committed, (3) after deleted
object is committed. Right now "preRemove" is called at (1). For
symmetry we can call it at (2). But then we need another callback for
(1). I just checked some of my use cases, and (1) is sort of an
important place - you can make some assertions about the object before
it is disassociated from its relationships via delete rules. I think I
already figured out how to deal with my case, not sure how such
removal of functionality would affect others?
BTW, if all we do is callback renaming/adding new callbacks, we can
provide DataMap migration ability via the Modeler.
Andrus
On Sep 24, 2009, at 6:08 AM, Robert Zeigler wrote:
Hm. Apologies, I haven't been following this thread very closely.
Preface: I realize JPA compatibility isn't necessarily a current
goal, but hear me out. :)
The way I read the JPA spec is that @PrePersist is supposed to be
called immediately before database insert.
The problem seems to be a mismatch between the "cayenne way" and the
"JPA" way. In cayenne, you register your object, then make your
changes (especially relationships), then commit to the DB. In JPA,
you would setup the entire bean structure (including relationships)
before calling EntityManager.persist, which results directly in a DB
commit. Ie, persist is like context.registerNewObject() +
context.commitChanges() rolled into one, except the scope is limited
a single object and associated changes.
I don't have any qualms about adding additional lifecycle listeners
to make cayenne more useful in general and/or to address the
impedence with JPA, but if we're going to keep lifecycle listeners
with the same names as the JPA ones, we should also keep the same
semantics, which means calling PrePersist immediately before
insert. Otherwise, we'll confuse users new to cayenne but familiar
with JPA. So, I would propose something more like:
postRegister <- called when a non-persisted object is registered
with a data context. You could even have a preRegister, but that's
probably overkill.
prePersist <- just before DB insert
postPersist <- just after DB insert
preUpdate < - just before DB update of existing object
postUpdate <- just after DB update
preRemove <- just before DB delete
postRemove <-just after DB delete
postLoad <- just after a committed obj. is fetched from the DB.
Alternatively, as mentioned below we could rename all callbacks to
align with the "cayenne way". But, again, if we're going to keep
the JPA names, we should keep the behavior as JPA-like as possible.
Robert