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:


15 comments:

  1. 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?

    ReplyDelete
  2. Hi,

    It applies second, if first doesn't succeed.

    Andrejus

    ReplyDelete
  3. 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!

    ReplyDelete
  4. 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

    ReplyDelete
  5. 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.

    ReplyDelete
  6. Hi,

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

    Andrejus

    ReplyDelete
  7. 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





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

    Andrejus

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

    Andrejus

    ReplyDelete
  10. Hi Andrejus,

    I have a VO with an attribute of EO which has several associated LOV. When I make undo as you define reevaluated all LOV and the attribute value (EO) is lost. In debug mode I found that the attribute that makes "LOVFinder" is properly informed at all times. Could you may be happening?

    Thank you very much.

    ReplyDelete
  11. I also have SQL based attribute that isn't getting refreshed. SQL subquery is across multiple tables and has where clause referencing another table in the view so I don't think I can put that in the EO as I wouldn't have reference to other entities needed. Any ideas how to do refresh without executing the full query.

    ReplyDelete
  12. I have similar issue to solve in my project. If I will find solution, I will post here.

    Regards,
    Andrejus

    ReplyDelete
  13. Hello Andrejus. Thanks for the post.
    Have you found the solution to what Don Kleppinger asks? (refresh current row without executing the full query - no rollback)

    Regards,
    Apostolos

    ReplyDelete
  14. You need to put calculate SQL based attribute into EO, it works then to refresh it.

    Andrejus

    ReplyDelete