cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From <do...@xsinet.co.za>
Subject Re: How to execute a stored procedure as part of a commitChanges?
Date Wed, 13 Apr 2016 08:29:17 GMT
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 ; dollj@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 
<jmdiazlr@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, "dollj@xsinet.co.za" 
<dollj@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 <johnthuss@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
<jmdiazlr@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 <johnthuss@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
> <jmdiazlr@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 <
> > mkienenb@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
> > <jmdiazlr@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
> > >
> > >
> > >
> > >
> >
> >
>
>






Mime
View raw message