Making sense of callbacks

34 messages Options
Embed this post
Permalink
1 2
Aristedes Maniatis

Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
Even though the callback system in Cayenne 3 is simple to explain (http://cayenne.apache.org/doc/lifecycle-callbacks.html 
  ) there are some details which can bite. I'd like to create an  
overview of how I think they currently work and what issues remain:

How we use them
---------------
* set createdOn attribute in all entities
* set modifiedOn attributed in all entities
* update calculated denormalised summary fields. For example, invoice  
lines are added and payments subtracted to create an invoiceOwing  
attribute. This needs to be updated whenever a relevant record is  
created or updated.
* audit trail records. Every time a change is made to a record, a log  
entry is created (we actually use this for database replication).
* firing special events - in our system when a new payment is created,  
special credit card processing code runs, all before the ROP client  
gets a return value from the context.commit().


Now, I understand that lifecycle is tied up tightly with JPA so some  
of the naming reflects names imposed by JPA. But hopefully Cayenne  
functionality could go further.


Cayenne 2 tier
--------------

For new objects :
context.newObject() -> prePersist()
context.commitChanges() -> postPersist()

For existing objects:
context.commitChanges() -> preUpdate(), postUpdate()



Cayenne 3 tier (ROP)
--------------------

For new objects :
context.commitChanges() -> prePersist(), postPersist()

For existing objects:
context.commitChanges() -> preUpdate(), postUpdate()


Object state
------------
prePersist() in 2 tier: object attributes and relationships are all null
prePersist() in ROP: object attributes populated but relationships  
always invalid

preUpdate(): attributes and relationships are all dependable. In  
addition, within the context being committed, we can follow a  
relationship from one object to another and see its new updated  
attributes.



Summary
-------

* prePersist() is only useful as a place to set object attributes  
(such as creationDate) since you cannot follow relations reliably in a  
ROP environment.

* postUpdate() and postPersist() are useful for changes which do not  
need to be committed atomically with the original commit. So good for  
creating log records, but not ideal for updating invoiceOwing.

* postPersist() is badly named. It is really postInsert()

* we need preInsert()


Additional callbacks
--------------------
preCommit() and postCommit() listeners on the context itself would be  
really useful. They should run AFTER the per object listeners have all  
run for that phase. This would be one per context and allow a single  
entry point which can examine and touch all objects in the context  
before commit or just after.


Additional ROP feature
----------------------
If an object is touched within a pre-commit phase on the server, the  
ROP client does not get the updated object refreshed automatically. It  
appears the response the client is either just the validation  
exception (if there is one) or "all OK". We are currently remembering  
to set the object on the client to be hollow, but it would be nice for  
the server to return all committed objects to the client.


I hope that I haven't tried to cover too much ground here. My purpose  
is to get some feedback about the above ideas, and about how hard they  
are to implement in Cayenne. Since this is a blocking issue for our  
main commercial project we are want to focus and getting these things  
clear in the Cayenne docs and making appropriate improvements.


Cheers
Ari Maniatis


-------------------------->
ish
http://www.ish.com.au
Level 1, 30 Wilson Street Newtown 2042 Australia
phone +61 2 9550 5001   fax +61 2 9550 4001
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A


Aristedes Maniatis

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink

On 29/11/2007, at 12:28 PM, Aristedes Maniatis wrote:

> Summary
> -------
>
> * prePersist() is only useful as a place to set object attributes  
> (such as creationDate) since you cannot follow relations reliably in  
> a ROP environment.
>
> * postUpdate() and postPersist() are useful for changes which do not  
> need to be committed atomically with the original commit. So good  
> for creating log records, but not ideal for updating invoiceOwing.
>
> * postPersist() is badly named. It is really postInsert()
>
> * we need preInsert()


With some further reading of the JPA specification I have come to the  
following conclusions:

* the JPA was written by lawyers who get paid by the word

* postPersist() is defined in the JPA to occur after a NEW record is  
written to the database. Which is how Cayenne works.

* pre/postUpdate(): the JPA specification is very very unclear, but it  
looks like maybe it might apply for both new and existing records. But  
then postUpdate() overlaps postPersist() which is a bit pointless.

* if preUpdate() is just for existing records we still need a  
preInsert().


So, even though we have to follow the poorly named callbacks in JPA,  
an extra callback would fill a useful hole.


Ari


-------------------------->
ish
http://www.ish.com.au
Level 1, 30 Wilson Street Newtown 2042 Australia
phone +61 2 9550 5001   fax +61 2 9550 4001
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A


Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink

On Nov 29, 2007, at 10:56 AM, Aristedes Maniatis wrote:

>>
>> * prePersist() is only useful as a place to set object attributes  
>> (such as creationDate) since you cannot follow relations reliably  
>> in a ROP environment.

True, and a workaround would be to support relationships for transient  
objects. Something Kevin was bringing up on multiple occasions.


>> * postUpdate() and postPersist() are useful for changes which do  
>> not need to be committed atomically with the original commit. So  
>> good for creating log records, but not ideal for updating  
>> invoiceOwing.

Another way to go about atomic commits is to set up a manual  
transaction that spans a request scope. I think that's an appropriate  
solution.

>> * postPersist() is badly named. It is really postInsert()
>> * we need preInsert()

per JPA "persist" is "insert", so the naming is correct if somewhat  
confusing.


> With some further reading of the JPA specification I have come to  
> the following conclusions:
>
> * the JPA was written by lawyers who get paid by the word

It is confusing. Tell me about it! But partially because of  
differences in perception of persistence between Cayenne and the  
frameworks with EJB background.


> * postPersist() is defined in the JPA to occur after a NEW record is  
> written to the database. Which is how Cayenne works.

Yep.

> * pre/postUpdate(): the JPA specification is very very unclear, but  
> it looks like maybe it might apply for both new and existing  
> records. But then postUpdate() overlaps postPersist() which is a bit  
> pointless.

I think this is left up to implementation to handle. Yes - confusing.

> * if preUpdate() is just for existing records we still need a  
> preInsert().

I wonder if we should just call "preUpdate" for new objects in  
addition to prePersist.

Andrus
Lachlan Deck

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
Hi there,

On 29/11/2007, at 11:22 PM, Andrus Adamchik wrote:

> On Nov 29, 2007, at 10:56 AM, Aristedes Maniatis wrote:
>
>>> * prePersist() is only useful as a place to set object attributes  
>>> (such as creationDate) since you cannot follow relations reliably  
>>> in a ROP environment.
>
> True, and a workaround would be to support relationships for  
> transient objects. Something Kevin was bringing up on multiple  
> occasions.

Yeah the prePersist on server (from ROP commit) would just give you a  
chance to initialise things that the client is unaware of I would've  
thought.

Otherwise, there are no relationships to follow, really... as they've  
not been initialised yet. i.e., it's a new object that's being  
initialised / inserted into a context. The fact that you see the  
attributes already populated on server when committing from the  
client is because the prePersist in 3 tier on server is really a  
second constructor (or third). i.e., in the real java constructor you  
do nothing because the object has not as yet been inserted into an  
editing context, in prePersist on client you initialise attributes/
relationships, in prePersist on server, you can initialise other  
stuff if needed... but you don't yet have in view the object as it  
was on the client (i.e., relationships aren't faulted).

That fulfils most general cases.

>>> * postUpdate() and postPersist() are useful for changes which do  
>>> not need to be committed atomically with the original commit. So  
>>> good for creating log records, but not ideal for updating  
>>> invoiceOwing.
>
> Another way to go about atomic commits is to set up a manual  
> transaction that spans a request scope. I think that's an  
> appropriate solution.

Making such changes in another context (in post[Persist|Update|
Remove]) seems like reasonable practice, the question is when will  
such changes be reflected in the former context.

>>> * postPersist() is badly named. It is really postInsert()
>>> * we need preInsert()
>
> per JPA "persist" is "insert", so the naming is correct if somewhat  
> confusing.

Hmm. Yeah I don't think it's badly named either. It's the  
counterpart, prePersist, that doesn't match conceptually (as with  
preUpdate) in terms of when it is fired. The point is that we're  
missing (logically) a callback.

i.e., there does need to be a callback that prePersist currently  
provides for when objects are initiated, but there's no complimentary  
callback to preUpdate for those new objects just prior to commit.  
Perhaps the JPA assumes you'll initiate your objects as per normal  
Java via Constructors and such whereas in Cayenne you don't touch the  
object until it's been inserted into a Context and thus the current  
prePersist is your constructor.

>> * if preUpdate() is just for existing records we still need a  
>> preInsert().
>
> I wonder if we should just call "preUpdate" for new objects in  
> addition to prePersist.

That doesn't sound like a nice fit. i.e., they're currently in nice  
pairs like:
preUpdate --> postUpdate
preRemove --> postRemove

It would seem (to me at least), then, that you'd want (fired at the  
same times as above):
prePersist --> postPersist

And replace current prePersist with something like postNew or  
postCreate or something.

So calling preUpdate would be better than nothing, if you're  
constrained by the JPA, but doesn't seem like the clean solution FWIW.

What do you think?

with regards,
--

Lachlan Deck

Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
In reply to this post by Aristedes Maniatis
Having run into some issues with callbacks myself and generally  
gaining better insight into callbacks patterns, I second what Ari has  
suggested two years ago in the message below. Namely I suggest the  
following changes:

1. call pre/postUpdate for new objects. So new objects will have pre/
postPersist as well as pre/postUpdate callbacks. Of course the main  
motivation is that preUpdate is called before save, not after context  
insert, so all the relationships are in place.

2. stop calling pre/postUpdate for removed objects. This is causing  
grief when we need to access relationships of a deleted object.

Both changes are actually still compatible with JPA spec, due to the  
vagueness mentioned below. This may affect the callbacks currently in  
use by 3.0 applications, so this is our last chance to slip it in  
before the beta, and also we need to make it clear what upgrade steps  
need to be taken by the current 3.0 users.

If there's no objections, I will work on such change.

(Also not sure how this affects ROP yet?)

Andrus


On Nov 29, 2007, at 10:56 AM, Aristedes Maniatis wrote:

> On 29/11/2007, at 12:28 PM, Aristedes Maniatis wrote:
>
>> Summary
>> -------
>>
>> * prePersist() is only useful as a place to set object attributes  
>> (such as creationDate) since you cannot follow relations reliably  
>> in a ROP environment.
>>
>> * postUpdate() and postPersist() are useful for changes which do  
>> not need to be committed atomically with the original commit. So  
>> good for creating log records, but not ideal for updating  
>> invoiceOwing.
>>
>> * postPersist() is badly named. It is really postInsert()
>>
>> * we need preInsert()
>
>
> With some further reading of the JPA specification I have come to  
> the following conclusions:
>
> * the JPA was written by lawyers who get paid by the word
>
> * postPersist() is defined in the JPA to occur after a NEW record is  
> written to the database. Which is how Cayenne works.
>
> * pre/postUpdate(): the JPA specification is very very unclear, but  
> it looks like maybe it might apply for both new and existing  
> records. But then postUpdate() overlaps postPersist() which is a bit  
> pointless.
>
> * if preUpdate() is just for existing records we still need a  
> preInsert().
>
>
> So, even though we have to follow the poorly named callbacks in JPA,  
> an extra callback would fill a useful hole.
>
>
> Ari
>
>
> -------------------------->
> ish
> http://www.ish.com.au
> Level 1, 30 Wilson Street Newtown 2042 Australia
> phone +61 2 9550 5001   fax +61 2 9550 4001
> GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
>
>
>

Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
> This is causing grief when we need to access relationships of a  
> deleted object.

Better wording: This is causing grief when we implement a post-update  
callback that needs to traverse relationships, and the object is  
already deleted, so no relationships are accessible.

On Sep 23, 2009, at 3:32 PM, Andrus Adamchik wrote:

> Having run into some issues with callbacks myself and generally  
> gaining better insight into callbacks patterns, I second what Ari  
> has suggested two years ago in the message below. Namely I suggest  
> the following changes:
>
> 1. call pre/postUpdate for new objects. So new objects will have pre/
> postPersist as well as pre/postUpdate callbacks. Of course the main  
> motivation is that preUpdate is called before save, not after  
> context insert, so all the relationships are in place.
>
> 2. stop calling pre/postUpdate for removed objects. This is causing  
> grief when we need to access relationships of a deleted object.
>
> Both changes are actually still compatible with JPA spec, due to the  
> vagueness mentioned below. This may affect the callbacks currently  
> in use by 3.0 applications, so this is our last chance to slip it in  
> before the beta, and also we need to make it clear what upgrade  
> steps need to be taken by the current 3.0 users.
>
> If there's no objections, I will work on such change.
>
> (Also not sure how this affects ROP yet?)
>
> Andrus
>
>
> On Nov 29, 2007, at 10:56 AM, Aristedes Maniatis wrote:
>> On 29/11/2007, at 12:28 PM, Aristedes Maniatis wrote:
>>
>>> Summary
>>> -------
>>>
>>> * prePersist() is only useful as a place to set object attributes  
>>> (such as creationDate) since you cannot follow relations reliably  
>>> in a ROP environment.
>>>
>>> * postUpdate() and postPersist() are useful for changes which do  
>>> not need to be committed atomically with the original commit. So  
>>> good for creating log records, but not ideal for updating  
>>> invoiceOwing.
>>>
>>> * postPersist() is badly named. It is really postInsert()
>>>
>>> * we need preInsert()
>>
>>
>> With some further reading of the JPA specification I have come to  
>> the following conclusions:
>>
>> * the JPA was written by lawyers who get paid by the word
>>
>> * postPersist() is defined in the JPA to occur after a NEW record  
>> is written to the database. Which is how Cayenne works.
>>
>> * pre/postUpdate(): the JPA specification is very very unclear, but  
>> it looks like maybe it might apply for both new and existing  
>> records. But then postUpdate() overlaps postPersist() which is a  
>> bit pointless.
>>
>> * if preUpdate() is just for existing records we still need a  
>> preInsert().
>>
>>
>> So, even though we have to follow the poorly named callbacks in  
>> JPA, an extra callback would fill a useful hole.
>>
>>
>> Ari
>>
>>
>> -------------------------->
>> ish
>> http://www.ish.com.au
>> Level 1, 30 Wilson Street Newtown 2042 Australia
>> phone +61 2 9550 5001   fax +61 2 9550 4001
>> GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
>>
>>
>>
>
>

Andrey Razumovsky

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
Hi Andrus,

I also suffered missing "preInsert" listener a number of times. But, I think
the moment of when listeners are called (and which of them are called)
should be easily guessed by what is happening to the object.

1. call pre/postUpdate for new objects. So new objects will have
>> pre/postPersist as well as pre/postUpdate callbacks. Of course the main
>> motivation is that preUpdate is called before save, not after context
>> insert, so all the relationships are in place.
>>
>>
So there will be four calls in total at object creation. I don't think it is
transparent that pre- and postUpdate will be called - after all, no updates
are ever made!


> 2. stop calling pre/postUpdate for removed objects. This is causing grief
>> when we need to access relationships of a deleted object.
>>
>
I'm confused. Are pre/postUpdate methods really called for deleted objects?
If this is so, it definitely must be stopped I think. Only pre/postRemove
should be called..

What will be wrong if we just add new type of event - preInsert? Users
aren't obligated to implement any listener class, after all. I'm afraid the
changes you suggest will break a lot of existing code

Thanks,
Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
Hi Andrey,

Thanks for your comments. This made me tweak my initial suggestion,  
resulting in something that hopefully makes more sense. So here is an  
attempt to show the full callback picture with suggested changes  
(grouping things by the object pre-commit state):

COMMITTED:
    postLoad

NEW:
    prePersist (called after registration in context)
    preInsert  (POTENTIAL NEW CALLBACK; called before commit) [1]
    postPersist (called after commit)

MODIFIED:
    preUpdate (called before commit)
    postUpdate (called after commit)

DELETED:
    preRemove (called before deleting in context, and before delete  
rules are evaluated)
    preUpdate (POTENTIAL REMOVED CALLBACK; called before commit) [2]
    postRemove (called after commit)
    postUpdate (POTENTIAL REMOVED CALLBACK; called after commit) [3]


[1] We definitely need this callback here for the new objects right  
before commit. My suggestion of reusing "preUpdate" here was based on  
the fact that all my pre-commit code for NEW and MODIFIED objects is  
exactly the same, so it seems that from implementation standpoint the  
event is almost identical. On the other hand, "postUpdate" is indeed  
redundant for NEW objects. So using pre/postUpdate for NEW does break  
the symmetry...

[2] While there's no overlap with a real "preUpdate" in possible  
callback functionality here, and we need to remove this one, this  
leaves a gap (just like with NEW objects) that needs to be filled with  
some "preCommitDeleted" callback.

[3] Definitely needs to be removed. It is being passed TRANSIENT  
objects and is really out of place (though still JPA compatible :-)).

I guess completely renaming callbacks to be aligned with Cayenne  
(rather than JPA) lifecycle could be a good thing (persist -> insert|
create, remove -> delete, etc.), and may go a long way in clarifying  
what is called and when. It is the end of a long day here, so I am not  
ready to suggest any better naming right away, but regardless of the  
naming, if we just make the changes above, I think we can provide the  
existing users a clear set of instructions on how to migrate existing  
callbacks to the new set. FWIW I'll be able to try it myself on a  
large application without waiting for the B1 release.

Andrus



On Sep 23, 2009, at 8:53 PM, Andrey Razumovsky wrote:

> Hi Andrus,
>
> I also suffered missing "preInsert" listener a number of times. But,  
> I think
> the moment of when listeners are called (and which of them are called)
> should be easily guessed by what is happening to the object.
>
> 1. call pre/postUpdate for new objects. So new objects will have
>>> pre/postPersist as well as pre/postUpdate callbacks. Of course the  
>>> main
>>> motivation is that preUpdate is called before save, not after  
>>> context
>>> insert, so all the relationships are in place.
>>>
>>>
> So there will be four calls in total at object creation. I don't  
> think it is
> transparent that pre- and postUpdate will be called - after all, no  
> updates
> are ever made!
>
>
>> 2. stop calling pre/postUpdate for removed objects. This is causing  
>> grief
>>> when we need to access relationships of a deleted object.
>>>
>>
> I'm confused. Are pre/postUpdate methods really called for deleted  
> objects?
> If this is so, it definitely must be stopped I think. Only pre/
> postRemove
> should be called..
>
> What will be wrong if we just add new type of event - preInsert? Users
> aren't obligated to implement any listener class, after all. I'm  
> afraid the
> changes you suggest will break a lot of existing code
>
> Thanks,

Lachlan Deck

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
On 24/09/2009, at 6:14 AM, Andrus Adamchik wrote:

> Hi Andrey,
>
> Thanks for your comments. This made me tweak my initial suggestion,  
> resulting in something that hopefully makes more sense. So here is  
> an attempt to show the full callback picture with suggested changes  
> (grouping things by the object pre-commit state):
>
> COMMITTED:
>   postLoad
>
> NEW:
>   prePersist (called after registration in context)
>   preInsert  (POTENTIAL NEW CALLBACK; called before commit) [1]
>   postPersist (called after commit)

The naming of these is a little less unintuitive though. What about:
postInsert (called after registration in context)
prePersist (called just before commit, but after validation)
postPersist (called after commit)

This - naming-wise - would fit better with the modified callbacks, no?

> MODIFIED:
>   preUpdate (called before commit)
>   postUpdate (called after commit)
>
> DELETED:
>   preRemove (called before deleting in context, and before delete  
> rules are evaluated)
>   preUpdate (POTENTIAL REMOVED CALLBACK; called before commit) [2]
>   postRemove (called after commit)
>   postUpdate (POTENTIAL REMOVED CALLBACK; called after commit) [3]
>
>
> [1] We definitely need this callback here for the new objects right  
> before commit. My suggestion of reusing "preUpdate" here was based  
> on the fact that all my pre-commit code for NEW and MODIFIED objects  
> is exactly the same, so it seems that from implementation standpoint  
> the event is almost identical. On the other hand, "postUpdate" is  
> indeed redundant for NEW objects. So using pre/postUpdate for NEW  
> does break the symmetry...
>
> [2] While there's no overlap with a real "preUpdate" in possible  
> callback functionality here, and we need to remove this one, this  
> leaves a gap (just like with NEW objects) that needs to be filled  
> with some "preCommitDeleted" callback.
>
> [3] Definitely needs to be removed. It is being passed TRANSIENT  
> objects and is really out of place (though still JPA compatible :-)).
>
> I guess completely renaming callbacks to be aligned with Cayenne  
> (rather than JPA) lifecycle could be a good thing (persist -> insert|
> create, remove -> delete, etc.), and may go a long way in clarifying  
> what is called and when. It is the end of a long day here, so I am  
> not ready to suggest any better naming right away, but regardless of  
> the naming, if we just make the changes above, I think we can  
> provide the existing users a clear set of instructions on how to  
> migrate existing callbacks to the new set. FWIW I'll be able to try  
> it myself on a large application without waiting for the B1 release.
>
> Andrus
>
>
>
> On Sep 23, 2009, at 8:53 PM, Andrey Razumovsky wrote:
>
>> Hi Andrus,
>>
>> I also suffered missing "preInsert" listener a number of times.  
>> But, I think
>> the moment of when listeners are called (and which of them are  
>> called)
>> should be easily guessed by what is happening to the object.
>>
>> 1. call pre/postUpdate for new objects. So new objects will have
>>>> pre/postPersist as well as pre/postUpdate callbacks. Of course  
>>>> the main
>>>> motivation is that preUpdate is called before save, not after  
>>>> context
>>>> insert, so all the relationships are in place.
>>>>
>>>>
>> So there will be four calls in total at object creation. I don't  
>> think it is
>> transparent that pre- and postUpdate will be called - after all, no  
>> updates
>> are ever made!
>>
>>
>>> 2. stop calling pre/postUpdate for removed objects. This is  
>>> causing grief
>>>> when we need to access relationships of a deleted object.
>>>>
>>>
>> I'm confused. Are pre/postUpdate methods really called for deleted  
>> objects?
>> If this is so, it definitely must be stopped I think. Only pre/
>> postRemove
>> should be called..
>>
>> What will be wrong if we just add new type of event - preInsert?  
>> Users
>> aren't obligated to implement any listener class, after all. I'm  
>> afraid the
>> changes you suggest will break a lot of existing code
>>
>> Thanks,
>

with regards,
--

Lachlan Deck



Lachlan Deck

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
In reply to this post by Andrus Adamchik
On 23/09/2009, at 10:32 PM, Andrus Adamchik wrote:

> (Also not sure how this affects ROP yet?)

Hopefully it'd mirror the server-side as closely as possible.

with regards,
--

Lachlan Deck

Aristedes Maniatis-2

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
On 24/09/09 10:16 AM, Lachlan Deck wrote:
> On 23/09/2009, at 10:32 PM, Andrus Adamchik wrote:
>
>> (Also not sure how this affects ROP yet?)
>
> Hopefully it'd mirror the server-side as closely as possible.

Some things to think about:

1. When an object is modified in a callback on the server, it should be updated by Cayenne automatically on the client. I don't think this currently happens.

2. When using ROP, the server side callbacks are a bit different. That is, you don't get prePersist until the object is committed, so I would propose that that callback be skipped completely on the server in ROP. Is this the sequence?

Client: prePersist
[user code to build and save context]
Client: preInsert
Server: preInsert
Server: postPersist
Client: postPersist

I think the naming is inconsistent: "persist", "insert" are used interchangably here.


Ari




--

-------------------------->
Aristedes Maniatis
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
Robert Zeigler-6

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
In reply to this post by Andrus Adamchik
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

On Sep 23, 2009, at 9/233:14 PM , Andrus Adamchik wrote:

> Hi Andrey,
>
> Thanks for your comments. This made me tweak my initial suggestion,  
> resulting in something that hopefully makes more sense. So here is  
> an attempt to show the full callback picture with suggested changes  
> (grouping things by the object pre-commit state):
>
> COMMITTED:
>   postLoad
>
> NEW:
>   prePersist (called after registration in context)
>   preInsert  (POTENTIAL NEW CALLBACK; called before commit) [1]
>   postPersist (called after commit)
>
> MODIFIED:
>   preUpdate (called before commit)
>   postUpdate (called after commit)
>
> DELETED:
>   preRemove (called before deleting in context, and before delete  
> rules are evaluated)
>   preUpdate (POTENTIAL REMOVED CALLBACK; called before commit) [2]
>   postRemove (called after commit)
>   postUpdate (POTENTIAL REMOVED CALLBACK; called after commit) [3]
>
>
> [1] We definitely need this callback here for the new objects right  
> before commit. My suggestion of reusing "preUpdate" here was based  
> on the fact that all my pre-commit code for NEW and MODIFIED objects  
> is exactly the same, so it seems that from implementation standpoint  
> the event is almost identical. On the other hand, "postUpdate" is  
> indeed redundant for NEW objects. So using pre/postUpdate for NEW  
> does break the symmetry...
>
> [2] While there's no overlap with a real "preUpdate" in possible  
> callback functionality here, and we need to remove this one, this  
> leaves a gap (just like with NEW objects) that needs to be filled  
> with some "preCommitDeleted" callback.
>
> [3] Definitely needs to be removed. It is being passed TRANSIENT  
> objects and is really out of place (though still JPA compatible :-)).
>
> I guess completely renaming callbacks to be aligned with Cayenne  
> (rather than JPA) lifecycle could be a good thing (persist -> insert|
> create, remove -> delete, etc.), and may go a long way in clarifying  
> what is called and when. It is the end of a long day here, so I am  
> not ready to suggest any better naming right away, but regardless of  
> the naming, if we just make the changes above, I think we can  
> provide the existing users a clear set of instructions on how to  
> migrate existing callbacks to the new set. FWIW I'll be able to try  
> it myself on a large application without waiting for the B1 release.
>
> Andrus
>
>
>
> On Sep 23, 2009, at 8:53 PM, Andrey Razumovsky wrote:
>
>> Hi Andrus,
>>
>> I also suffered missing "preInsert" listener a number of times.  
>> But, I think
>> the moment of when listeners are called (and which of them are  
>> called)
>> should be easily guessed by what is happening to the object.
>>
>> 1. call pre/postUpdate for new objects. So new objects will have
>>>> pre/postPersist as well as pre/postUpdate callbacks. Of course  
>>>> the main
>>>> motivation is that preUpdate is called before save, not after  
>>>> context
>>>> insert, so all the relationships are in place.
>>>>
>>>>
>> So there will be four calls in total at object creation. I don't  
>> think it is
>> transparent that pre- and postUpdate will be called - after all, no  
>> updates
>> are ever made!
>>
>>
>>> 2. stop calling pre/postUpdate for removed objects. This is  
>>> causing grief
>>>> when we need to access relationships of a deleted object.
>>>>
>>>
>> I'm confused. Are pre/postUpdate methods really called for deleted  
>> objects?
>> If this is so, it definitely must be stopped I think. Only pre/
>> postRemove
>> should be called..
>>
>> What will be wrong if we just add new type of event - preInsert?  
>> Users
>> aren't obligated to implement any listener class, after all. I'm  
>> afraid the
>> changes you suggest will break a lot of existing code
>>
>> Thanks,
>

Andrey Razumovsky

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
I feel the most comfortable with Robert's suggestion. Currently it is very
unintuitive that postPersist is called miles away from prePersist (and might
be not called at all). This will require some revision of already written
listeners, but it's quite benign.

2009/9/24 Robert Zeigler <[hidden email]>

> 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
>
>
> On Sep 23, 2009, at 9/233:14 PM , Andrus Adamchik wrote:
>
>  Hi Andrey,
>>
>> Thanks for your comments. This made me tweak my initial suggestion,
>> resulting in something that hopefully makes more sense. So here is an
>> attempt to show the full callback picture with suggested changes (grouping
>> things by the object pre-commit state):
>>
>> COMMITTED:
>>  postLoad
>>
>> NEW:
>>  prePersist (called after registration in context)
>>  preInsert  (POTENTIAL NEW CALLBACK; called before commit) [1]
>>  postPersist (called after commit)
>>
>> MODIFIED:
>>  preUpdate (called before commit)
>>  postUpdate (called after commit)
>>
>> DELETED:
>>  preRemove (called before deleting in context, and before delete rules are
>> evaluated)
>>  preUpdate (POTENTIAL REMOVED CALLBACK; called before commit) [2]
>>  postRemove (called after commit)
>>  postUpdate (POTENTIAL REMOVED CALLBACK; called after commit) [3]
>>
>>
>> [1] We definitely need this callback here for the new objects right before
>> commit. My suggestion of reusing "preUpdate" here was based on the fact that
>> all my pre-commit code for NEW and MODIFIED objects is exactly the same, so
>> it seems that from implementation standpoint the event is almost identical.
>> On the other hand, "postUpdate" is indeed redundant for NEW objects. So
>> using pre/postUpdate for NEW does break the symmetry...
>>
>> [2] While there's no overlap with a real "preUpdate" in possible callback
>> functionality here, and we need to remove this one, this leaves a gap (just
>> like with NEW objects) that needs to be filled with some "preCommitDeleted"
>> callback.
>>
>> [3] Definitely needs to be removed. It is being passed TRANSIENT objects
>> and is really out of place (though still JPA compatible :-)).
>>
>> I guess completely renaming callbacks to be aligned with Cayenne (rather
>> than JPA) lifecycle could be a good thing (persist -> insert|create, remove
>> -> delete, etc.), and may go a long way in clarifying what is called and
>> when. It is the end of a long day here, so I am not ready to suggest any
>> better naming right away, but regardless of the naming, if we just make the
>> changes above, I think we can provide the existing users a clear set of
>> instructions on how to migrate existing callbacks to the new set. FWIW I'll
>> be able to try it myself on a large application without waiting for the B1
>> release.
>>
>> Andrus
>>
>>
>>
>> On Sep 23, 2009, at 8:53 PM, Andrey Razumovsky wrote:
>>
>>  Hi Andrus,
>>>
>>> I also suffered missing "preInsert" listener a number of times. But, I
>>> think
>>> the moment of when listeners are called (and which of them are called)
>>> should be easily guessed by what is happening to the object.
>>>
>>> 1. call pre/postUpdate for new objects. So new objects will have
>>>
>>>> pre/postPersist as well as pre/postUpdate callbacks. Of course the main
>>>>> motivation is that preUpdate is called before save, not after context
>>>>> insert, so all the relationships are in place.
>>>>>
>>>>>
>>>>>  So there will be four calls in total at object creation. I don't think
>>> it is
>>> transparent that pre- and postUpdate will be called - after all, no
>>> updates
>>> are ever made!
>>>
>>>
>>>  2. stop calling pre/postUpdate for removed objects. This is causing
>>>> grief
>>>>
>>>>> when we need to access relationships of a deleted object.
>>>>>
>>>>>
>>>>  I'm confused. Are pre/postUpdate methods really called for deleted
>>> objects?
>>> If this is so, it definitely must be stopped I think. Only pre/postRemove
>>> should be called..
>>>
>>> What will be wrong if we just add new type of event - preInsert? Users
>>> aren't obligated to implement any listener class, after all. I'm afraid
>>> the
>>> changes you suggest will break a lot of existing code
>>>
>>> Thanks,
>>>
>>
>>
>


--
Andrey
Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
In reply to this post by Robert Zeigler-6
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

Aristedes Maniatis-2

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
On 24/09/09 6:08 PM, Andrus Adamchik wrote:
> 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)

Or, to take Robert's suggestion, we leave the existing callbacks in place and don't touch them since they are the JPA terms. New stuff can have brand new names.

To make a much more radical suggestion:

Working within the context:
onAddToContext  [postRegister at the moment]
onRemoveFromContext   [doesn't exist now, but seems symmetrical]

onDelete  [deleted in context]

beforeCommit  [preRemove, prePersist and preUpdate together]
afterCommit  [postRemove, postPersist and postUpdate together]

onFetch   [postLoad at the moment]


If we use words (like "commit") which already have meaning to Cayenne users, then it is very clear what is going on and it separates them from the JPA words. Then our docs have a little table with two columns, showing where our terms match the JPA terms exactly and where they differ. Avoiding "pre" and "post" completely keeps our terms quite separate. Then we don't even need to deprecate the JPA terms at all, just keep them as an 'alias' to Cayenne terms where appropriate.

Let me explain my rationale for merging remove, persist and update. It is easily possible within the callback itself to determine the state of the object, so the user can write code which branches appropriately. We find ourselves needing to link both persist and update together anyway, because it is likely that the same code will run for both. Next, the user action which caused the callback to happen was commit(), so it just makes logical sense. Finally, it means that the context itself can have its own beforeCommit and afterCommit callbacks (with the same names so it all makes consistent sense!):

beforeCommit -> object A
beforeCommit -> object B
beforeCommit -> context
...DB activity...
afterCommit -> object A
afterCommit -> object B
afterCommit -> context


This is a bit more work in the modeller to keep both JPA and Cayenne callbacks clear, but the end result might be more understandable, even if we end up with beforeCommitDelete, beforeCommitInsert, beforeCommitUpdate.


Ari


--

-------------------------->
Aristedes Maniatis
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
I am +1 on:

* Radical renaming if that helps us with consistency.
* The observation that pre/postCommit for NEW and MODIFIED objects are  
often identical (in my use cases they are always identical). Wonder in  
what case it is important to distinguish in postCommit whether the  
object was new or modified before commit?

I am -1 on:

* Keeping two parallel sets of callbacks. The only purpose it serves  
is compatibility with 3.0MN releases (N <= 6), and the need to  
maintain it going forward outweighs it in my mind. Also triggering  
callbacks is not free performance-wise, even for those events that  
have no registered listeners, so extra callback types will  
(marginally) slow things down. This will also allow us to use "pre/
post" prefixes for the names, as there won't parallel conflicting set  
of callbacks.

* Mixing pre/postCommit for DELETED with NEW/MODIFIED. The object  
state at the end of the commit is different (TRANSIENT for DELETED,  
COMMITTED for NEW/MODIFIED), so callbacks are almost never the same.

I am +/-0 on:

* Callbacks on contexts. Could be a good idea to have listeners  
attached to a context (although I don't see any use for context's own  
callback methods). I suggest we keep that in mind, but push it to the  
future releases to avoid adding new concepts to 3.0 at this point.


Conclusion:

So mixing Ari's idea with my points above, we have something like that:

* postLoad

* postAdd   ("post" as it is invoked after object is added to the  
context)
* preDelete ("pre" as it is invoked before delete rules are processed  
and before the object state is changed)

* preCommit
* preCommitDeleted
* postCommit
* postCommitDeleted

... or we can go completely the Cayenne way and change the callback  
signatures to take an enum characterizing the event nature, or even  
some sort of an event object.

And another idea. Once we settle on the nature of the change on this  
list, we write a migration guide draft for the users and take this  
discussion to the user@ list to see if the wider community can uncover  
any holes in the new design, or if there are other use cases that we  
haven't thought of.

Andrus



On Sep 24, 2009, at 12:54 PM, Aristedes Maniatis wrote:

> On 24/09/09 6:08 PM, Andrus Adamchik wrote:
>> 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)
>
> Or, to take Robert's suggestion, we leave the existing callbacks in  
> place and don't touch them since they are the JPA terms. New stuff  
> can have brand new names.
>
> To make a much more radical suggestion:
>
> Working within the context:
> onAddToContext  [postRegister at the moment]
> onRemoveFromContext   [doesn't exist now, but seems symmetrical]
>
> onDelete  [deleted in context]
>
> beforeCommit  [preRemove, prePersist and preUpdate together]
> afterCommit  [postRemove, postPersist and postUpdate together]
>
> onFetch   [postLoad at the moment]
>
>
> If we use words (like "commit") which already have meaning to  
> Cayenne users, then it is very clear what is going on and it  
> separates them from the JPA words. Then our docs have a little table  
> with two columns, showing where our terms match the JPA terms  
> exactly and where they differ. Avoiding "pre" and "post" completely  
> keeps our terms quite separate. Then we don't even need to deprecate  
> the JPA terms at all, just keep them as an 'alias' to Cayenne terms  
> where appropriate.
>
> Let me explain my rationale for merging remove, persist and update.  
> It is easily possible within the callback itself to determine the  
> state of the object, so the user can write code which branches  
> appropriately. We find ourselves needing to link both persist and  
> update together anyway, because it is likely that the same code will  
> run for both. Next, the user action which caused the callback to  
> happen was commit(), so it just makes logical sense. Finally, it  
> means that the context itself can have its own beforeCommit and  
> afterCommit callbacks (with the same names so it all makes  
> consistent sense!):
>
> beforeCommit -> object A
> beforeCommit -> object B
> beforeCommit -> context
> ...DB activity...
> afterCommit -> object A
> afterCommit -> object B
> afterCommit -> context
>
>
> This is a bit more work in the modeller to keep both JPA and Cayenne  
> callbacks clear, but the end result might be more understandable,  
> even if we end up with beforeCommitDelete, beforeCommitInsert,  
> beforeCommitUpdate.
>
>
> Ari
>
>
> --
>
> -------------------------->
> Aristedes Maniatis
> GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
>

Lachlan Deck

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
On 28/09/2009, at 12:13 AM, Andrus Adamchik wrote:

> I am +1 on:
>
> * Radical renaming if that helps us with consistency.
> * The observation that pre/postCommit for NEW and MODIFIED objects  
> are often identical (in my use cases they are always identical).  
> Wonder in what case it is important to distinguish in postCommit  
> whether the object was new or modified before commit?

I'm hoping these combined callbacks are not replacing individual ones.

> <..>
> Conclusion:
>
> So mixing Ari's idea with my points above, we have something like  
> that:
>
> * postLoad
>
> * postAdd   ("post" as it is invoked after object is added to the  
> context)
> * preDelete ("pre" as it is invoked before delete rules are  
> processed and before the object state is changed)
If you're going that way you'd need a preUpdate to match (wouldn't  
you?) to keep it balanced.

> * preCommit
> * preCommitDeleted
> * postCommit
> * postCommitDeleted
>
> ... or we can go completely the Cayenne way and change the callback  
> signatures to take an enum characterizing the event nature, or even  
> some sort of an event object.

Not personally keen on if-else based lifecycle callbacks... but I  
suppose everyone's superclass can call the relevant signature.

Just to review the thread.... I'm not sure such a drastic change is  
needed to make lifecycle callbacks complete/useful. There was one  
(maybe two) missing and some adjusted behaviour / clarification needed  
overall, no(?) rather than a complete change?

i.e., it seems to me it's mostly good but with some gaps
postLoad .. after fetch

prePersist ... should be instead called (whether ROP or not) after  
validateForSave but before persisting a new object
preUpdate ... as now, after validation and before persisting updates  
to an already persisted object
preDelete ... again after validation but prior to deleting from the  
objectstore

postPersist
postUpdate
postDelete .. all logically matching their pre counterparts.

what's missing?
postInsert .. called after an object is created and inserted into a  
context

So from what I can see the only two changes required were 'postInsert'  
and adjusting the meaning of prePersist

with regards,
--

Lachlan Deck

Aristedes Maniatis-2

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
On 28/09/09 11:08 AM, Lachlan Deck wrote:
> So from what I can see the only two changes required were 'postInsert'
> and adjusting the meaning of prePersist

I think most of the discussion started from the point that we shouldn't 'adjust' the meaning of an event which is defined by JPA since it will be confusing to users from a JPA background.

I'm not wedding to the idea I proposed: it was more to stimulate some thinking about what a completely fresh approach might look like. But thinking about it, the problem with beforeCommit as a name is that it will not have effect when committing child contexts, so it is potentially confusing.

Lachlan's idea of keeping the changes minimal might be the simplest one for users.


On 28/09/09 12:13 AM, Andrus Adamchik wrote:
> * Callbacks on contexts. Could be a good idea to have listeners attached
> to a context (although I don't see any use for context's own callback
> methods). I suggest we keep that in mind, but push it to the
> future releases to avoid adding new concepts to 3.0 at this point.

Certainly it should be postponed, but thought about now so we have a plan. The use for this type of listener is when you want to inspect the entire context before commit rather than look at the commit per object. As an example in one of our projects we added a whole lot of code server-side (ROP) on saving a new Payment object, which checked to see if it was a credit card payment and then performed some action (like contacting the bank, checking for places available, etc). But we found that when we had a free product there was no Payment, but we still wanted to check for places available. So a hook at a context level could have been useful to identify that the commit was of new enrolments/students/etc and then allow the code to check for places, process payment, etc As it is, we worked around the problem by creating a $0 Payment, just so the listener and all our code could be fired off in a consistent way.

We could have alternately created a different servlet call or used several other approaches, so it was never a big issue, just a potential use-case.


Anyhow, I've said enough about this topic and I don't want this to turn into a bikeshed... I'm happy with whatever Andrus implements, which will be a good improvement whichever way is chosen.


Ari Maniatis

--

-------------------------->
Aristedes Maniatis
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A
Andrus Adamchik

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
In reply to this post by Lachlan Deck

On Sep 28, 2009, at 4:08 AM, Lachlan Deck wrote:

>
> So from what I can see the only two changes required were  
> 'postInsert' and adjusting the meaning of prePersist

I also tend to think that less is better. This discussion thread was a  
nice brainstorming on the callbacks use patterns. So we've played with  
a few things and now I am fine if we go a full circle to the minimal  
change suggested earlier, and don't worry about JPA users, extra  
delete callbacks, or symmetry between callback types (in many respects  
there's little symmetry if you look at the object lifecycle - http://cayenne.apache.org/doc/persistent-object-lifecycle.html)
.

So here is the change I am going to make:

1. Call "prePersist" before commit
2. Introduce "postAdd" instead of current "prePersist".

This change is minimal and is not incompatible with other ideas.  
Objections?

Andrus


Lachlan Deck

Re: Making sense of callbacks

Reply Threaded More More options
Print post
Permalink
On 28/09/2009, at 4:53 PM, Andrus Adamchik wrote:

> On Sep 28, 2009, at 4:08 AM, Lachlan Deck wrote:
>
>>
>> So from what I can see the only two changes required were  
>> 'postInsert' and adjusting the meaning of prePersist
>
> I also tend to think that less is better. This discussion thread was  
> a nice brainstorming on the callbacks use patterns. So we've played  
> with a few things and now I am fine if we go a full circle to the  
> minimal change suggested earlier, and don't worry about JPA users,  
> extra delete callbacks, or symmetry between callback types (in many  
> respects there's little symmetry if you look at the object lifecycle  
> - http://cayenne.apache.org/doc/persistent-object-lifecycle.html).
>
> So here is the change I am going to make:
>
> 1. Call "prePersist" before commit
> 2. Introduce "postAdd" instead of current "prePersist".
>
> This change is minimal and is not incompatible with other ideas.  
> Objections?

No objections - just a suggestion that whilst looking at this stuff  
it'll be good to review ROP's behaviour with callbacks such that it's  
consistent with the server-side.

with regards,
--

Lachlan Deck



1 2