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

Reply via email to