Saturday, May 12, 2012

Refreshing Single Row Without Full Rollback

With ADF Rollback operation - ADF is reloading entire dataset from DB. It invokes ROLLBACK from database and then executes View Object to return latest data from DB for all rows. This works well when we want to undo multiple changes at once. It may happen to encounter such use case, where we need to undo changes per row, not per set of rows. This is possible in ADF as well - using refresh(...) method for ADF BC Row. But keep in mind, while this method refreshes selected row - it never cleans up ADF BC transaction, it will remain dirty. This is logical - ADF BC doesn't know, if there are other changed rows. This means - you should provide to the user both buttons:

1. Undo - will rollback changes for all rows and mark transaction clean (standard Rollback operation)
2. Undo Row - will refresh only selected row and keep transaction dirty (Described in this post)

In this post I will describe how to refresh selected row, download sample application - RowHighlight_v2.zip. This application is extended version of my previous sample from this post - Changed Row Highlighting in Oracle ADF Table.

We will see first, how ADF BC performs when executing standard Rollback operation. There are three rows changed, row selection is on last row:


Press Undo to invoke Rollback operation, when operation is completed - changes are cleared from all rows as expected, but there is side effect - row selection is lost and reset to point to the first row:


If we check in the log, there is plain SQL statement executed for entire data collection - without bind variable restriction, this re-executes View Object:


Will demo now, how single row refresh works. User needs to select row, where changes should be cleared:


Press Undo Row button - changes for the selected row will be cleared, without affecting existing changes for other rows. Its very important - row selection will stay on the same row as it was before invoking Undo Row operation:



Now we can see different picture in the log - ADF BC executes SQL restricted by bind variable and fetches only data for specific row we are refreshing. This will perform much better comparing to standard Rollback operation:


Single row refresh is implemented as custom method inside View Object implementation class. For current row we are calling refresh operation with REFRESH_UNDO_CHANGES and REFRESH_WITH_DB_FORGET_CHANGES arguments - this will force to reload current row cache:


This method is exposed through View Object client interface and is accesible from Data Control:


Method is declared in Page Definition:


Is invoked from Managed Bean action method:


10 comments:

Jordi said...

Hello,

what would be the difference between refresh(REFRESH_UNDO_CHANGES | REFRESH_WITH_DB_FORGET_CHANGES) as you do, and refresh(REFRESH_WITH_DB_FORGET_CHANGES)? I have read these constants' documentation, and since REFRESH_UNDO_CHANGES may only rollback until the last posted data in the transaction, and REFRESH_WITH_DB_FORGET_CHANGES will always rollback to the last commited data, it kind of cancels the other one, doesn't it?

Andrejus Baranovskis said...

Hi,

It applies second, if first doesn't succeed.

Andrejus

Sathya said...

Hi Andrejus,

Nice post. I am having a table which renders only one row at runtime and I have overridden the rowSelection listener with a managed bean. However, the method is not invoked when there is only one row (i think row state is not changed). How do I get around this problem? Any suggestions? Thanks!

Amit Agrawal said...

Hi Andrejus,

I used REFRESH_UNDO_CHANGES to reset my form which was having cascading LOV'S using view accessor instead of doing a rollback due to its rollback side effects. But after this call, my row was getting refreshed but the view accessors were not getting changed. Does some special steps need to be taken to refresh view accessors.

Thanks
Amit

Onkar S said...

Perfect. Thanks

ILya Cyclone said...

Hello Andrejus,
Got a surprising result: after doing this kind of refresh from a requestScope bean all my calculated attributes become null.
Why is that happening?
-----------------------------
Row row = ADFUtils.findIterator(...).getCurrentRow();
System.out.println(row.getAttribute("EntityBoundAttribute")+"; "+row.getAttribute("CalcedAttribute")); // --> 20; 10
row.refresh(Row.REFRESH_UNDO_CHANGES | Row.REFRESH_WITH_DB_FORGET_CHANGES);
System.out.println(row.getAttribute("EntityBoundAttribute")+"; "+row.getAttribute("CalcedAttribute")); // --> 20; null
-----------------------------
Is this method at all fine not just to cancel changes but really to refresh a row from DB without full requery?

Thanks.

Andrejus Baranovskis said...

Hi,

What expression you are using for calculated attribute, is it based on SQL expression or something in Groovy?

Andrejus

ILya Cyclone said...

Andrejus, I've tried two different SQL-calculated attributes and both of them turned null (in bean code and in UI) after refresh.

Nothing special about the attribute, eg: (select count(*) from ...) as METATERMS_COUNT





Andrejus Baranovskis said...

I will need to test this, I will try to do it today. Will post update then.

Andrejus

Andrejus Baranovskis said...

Yes, I reproduced your case. But when I move SQL based attribute to EO - it seems to work, try it.

Andrejus