Not completely germane to the discussion, but keep in mind that
modifiedObjects() can return far more objects than you expect since it
includes all phantom changes:

user.gerFirstName() => "John"
user.setFirstName("John") => Modified Object/Phantom Change

These types of phantom changes happen quite frequently in web-applications
during FORM submissions as the value is blindly set again while processing
the FORM, even if the value didn't change.

It is a CPU/RAM trade-off.  If you think you might have a lot of phantom
changes and RAM usage is more of a concern than CPU usage, you'll want to
prune out the phantom changes.

mrg


On Wed, Apr 13, 2016 at 4:29 AM, <do...@xsinet.co.za> wrote:

> Hi Juan
>
> You can use context.modifiedObjects() to get a list of objects that have
> changed and then process each one, something like:
>
> Map<CayenneDataObject,DataRow>  changeMap = new HashMap<>();
>
> for ( CayenneDataObject dataObj : (List<CayenneDataObject>)
> context.modifiedObjects() )
> {
>    DataRow  changes = context.currentSnapshot( dataObj ).createDiff
>    (
>        context.getObjectStore().getSnapshot( dataObj.getObjectId() )
>    );
>
>    changeMap.put( dataObj, changes );
> }
>
>
> And then on failure:
>
>
> for ( Entry<CayenneDataObject,DataRow> changEntry : changeMap.entrySet() )
> {
>    context.rollbackChanges();
>    context.currentSnapshot( changEntry.getKey() ).applyDiff(
> changEntry.getValue() );
> }
>
>
> You can also get a list of new and deleted objects in a context with:
> context.deletedObjects();
> context.newObjects();
>
> Regards
> Jurgen
>
>
> -----Original Message----- From: Juan Manuel Diaz Lara
> Sent: Wednesday, April 13, 2016 1:31 AM
> To: user@cayenne.apache.org ; Juan Manuel Diaz Lara ; do...@xsinet.co.za
>
> Subject: Re: How to execute a stored procedure as part of a commitChanges?
>
> Jurgen, your code is great for one dataobject, but how to do it for the
> entire context automatically ?
> Atte. Juan Manuel Díaz Lara
>
>    On Tuesday, April 12, 2016 2:04 PM, Juan Manuel Diaz Lara
> <jmdia...@yahoo.com.INVALID> wrote:
>
>
> Thanks, I will try it this later, report results.
> Atte. Juan Manuel Díaz Lara
>
>    On Tuesday, April 12, 2016 5:16 AM, "do...@xsinet.co.za" <
> do...@xsinet.co.za> wrote:
>
>
> Hi Juan
>
> With regards to your question:  is there some way to get a diff of the
> failed context and apply that to the new context ?
>
> You could try the following:
>
> 1.  Before context.commitChanges() do something like:
>
> DataRow  changes = context.currentSnapshot( this ).createDiff
> (
>    context.getObjectStore().getSnapshot( getObjectId() )
> );
>
> 2.  On failure do:
>
> context.rollbackChanges();
> context.currentSnapshot( this ).applyDiff( changes );
>
> Then you should be back to where you started before the attempted commit.
>
> Regards
> Jurgen
>
>
>
>
> -----Original Message----- From: Juan Manuel Diaz Lara
> Sent: Tuesday, April 12, 2016 4:59 AM
> To: user@cayenne.apache.org
> Subject: Re: How to execute a stored procedure as part of a commitChanges?
>
> The fact is that the persistenceState of dataobjects is being set to
> COMMITTED before the actual transaction (db transaction or whatever) is
> committed, specially when running commitChanges()  inside
> performInTransaction() for the purpose to run additional code inside the
> same transaction and after commitChanges(). Think of a rich client
> application with many changes, additions and deletions before we can
> commit,
> it is not easy to replay this operations on a new context to retry all
> after
> making some corrections (or is there some way to get the a diff of the
> failed context and apply then to the new context ?).
>
> Elaborating on hacking cayenne, I found we can inject a new
> TransactionFactory and new ObjecStoreFactory on ServerRuntime, so it is
> possible to extend cayenne. I think i can install a new ObjectStore with a
> modified postprocessAfterCommit(GraphDiff) that runs its code after
> currentTransactionCommits. My hope is that if the transaction fails after
> commitChanges() then we can prevent  postprocessAfterCommit to run and so
> the context wil remain in the state it was before commitChanges(), after
> that we can retry the transaction (on the same context) after making some
> more changes.
>
> I need help with:
> 1. is this the only change needed considering other things like
> DataChannelFilters ?2. what about the interaction with nested context? how
> to care of this ?3. what do i need to do on rollback ?
>
> Thanks.
> Atte. Juan Manuel Díaz Lara
>
>    On Monday, April 11, 2016 3:21 PM, John Huss <johnth...@gmail.com>
> wrote:
>
>
> I think changing Cayenne is the wrong solution here.
>
> The problem is that your commit failed. You have to rollback the context if
> you want to keep using it.
>
> On Mon, Apr 11, 2016 at 2:22 PM Juan Manuel Diaz Lara
> <jmdia...@yahoo.com.invalid> wrote:
>
> Calling rollbackChanges will lost all changes, and create a new context
>> and start over is complex  with many and variables changes to replicate in
>> the new context...
>> I think the problem is that sync with db state is lost if the dataobjects
>> are market commited before the real transaction commits, in fact, this
>> what
>> the code in ObjectStore that change the persistentceState:
>>      * Internal unsynchronized method to process objects state after
>> commit.
>>      *
>>      * @since 1.2
>>      */
>>    void postprocessAfterCommit(GraphDiff parentChanges) {
>> but that is not true, because transaction commits happen after this code
>> runs no before as implied.
>>
>>  I am considering some hacking along the lines:
>> 1. Allow Transaction to execute arbitrary code after commit.2. ObjectStore
>> now should register with current transaction to run postprocessAfterCommit
>> after the transaction commits;
>> Well this is the idea, but I need more guide to do this, maybe not the
>> right classes to hack o derive, how to install my changes in a modular
>> way,
>> etc., I am really new to cayenne.
>>  Atte. Juan Manuel Díaz Lara
>>
>>    On Monday, April 11, 2016 11:04 AM, John Huss <johnth...@gmail.com>
>> wrote:
>>
>>
>>  Try calling context.rollbackChanges() or just create a new context and
>> start over.
>>
>> On Mon, Apr 11, 2016 at 10:31 AM Juan Manuel Diaz Lara
>> <jmdia...@yahoo.com.invalid> wrote:
>>
>> >
>> >
>> > I am using 4.0.M3.
>> > I used the following solution, but the problem is that after
>> > commitChanges() the dataobjetcs are set to PersistenceState.COMMITED, if
>> > the stored procedure fails Cayenne does a DB rollback (that's ok), but
>> > dataobjects stay COMMITED, so I can not retry the this transaction after
>> > errors are solved.
>> > Is there any way to revert the persistenceState to their values before
>> > commitChanges if I detect the stored procedure failed ?
>> >
>> >            cayenneRuntime.performInTransaction(new
>> > TransactionalOperation<Integer>()
>> >                    {
>> >
>> >                        @Override
>> >                        public Integer perform() {
>> >                            context.commitChanges();
>> >                            //...
>> >                            SQLTemplate s = new SQLTemplate("SELECT
>> > pkg_inventario_fisico.apply( #bind($idAlmacen, 'VARCHAR')) AS id",
>> > true);
>> >                            s.setParamsArray(a);
>> >                            @SuppressWarnings("unchecked")
>> >                            List<DataRow> rows =
>> > CayenneDao.instance.context.performQuery(s);
>> >                            DataRow row = rows.get(0);
>> >                            //...
>> >                            return null;
>> >                        }
>> >
>> >                    }
>> >            );
>> >  Atte. Juan Manuel Díaz Lara
>> >
>> >    On Monday, April 11, 2016 10:06 AM, Mike Kienenberger <
>> > mkien...@gmail.com> wrote:
>> >
>> >
>> >  See the bottom part of this page starting at "In the second scenario":
>> >
>> >
>> >
>>
>> https://cayenne.apache.org/docs/4.0/cayenne-guide/persistent-objects-objectcontext.html#transactions
>> >
>> >
>> > On Mon, Apr 11, 2016 at 10:54 AM, Juan Manuel Diaz Lara
>> > <jmdia...@yahoo.com.invalid> wrote:
>> > >
>> > >
>> > >  I have a dataobjet graph with some changes, and a db stored procedure
>> > that should run after this changes are in the db, but must run in the
>> same
>> > transaction because it make some more changes to other data, this
>> > changes
>> > can fail so I want the commitChanges fail if the stored procedure fails.
>> > >  Atte. Juan Manuel Díaz Lara
>> > >
>> > >
>> > >
>> > >
>> >
>> >
>>
>>
>>
>
>
>
>
>

Reply via email to