31 Mar 2013

Unneeded queries in association accessor

Let's consider some master-detail form representing a customer order:

So, there are two entities connected to each other with an 1..* association. The master entity contains an association accessor returning a row set of detail entities:
public RowIterator getCustomorderitem()
    return (RowIterator) getAttributeInternal(CUSTOMORDERITEM);

And, for example, we need to run through the detail rows before posting master entity to the database and do some job:
  protected void prepareForDML(int operation, TransactionEvent e) {
    super.prepareForDML(operation, e);
    RowIterator ri = getCustomorderitem();
    while (ri.hasNext()) {
      CustomorderitemImpl item = (CustomorderitemImpl) ri.next();
      //do some job ...

In order to prepare and return the row iterator with detail entity rows the framework creates some internal view object, attaches it to the association and queries the database for the required rows. If the "association consistency" mode is on, the framework applies modified rows to the rows fetched from the database.  So, if we do any modifications with order items in our form, the framework takes care of these modifications and includes them to the row iterator. And everything seems to be ok, but the framework executes the database query each time whenever we ask for the association accessor. The question is - do we really need that? Do we really need to ask the database for the rows that we already have in memory and represent in UI? In most cases we don't . In order to prevent these unneeded queries we can change the query mode of the internal VO to be executed in memory:

  public RowIterator getCustomorderitem()
    RowSet rs = (RowSet) getAttributeInternal(CUSTOMORDERITEM);
    return rs;

That's it!

17 Mar 2013

Association Consistency and View Criterias

There is very powerful and useful feature in ADF BC - "association consistency". It guaranties that when we create a new entity row or update an entity attribute, this change is going to be replicated to the view objects based on this entity.
Let's say, for example, we have two view objects VListDept and VRecordDebt based on the same entity Departments. We use the VListDept view object on a browse view activity with a table component, and VRecordDebt view object is used on create/update view activities. So, when we create a new record via the VRecordDebt view object, we expect it to appear in the VListDept view object, because it is based on the same entity. This is the default framework behavior, we rely on it and design our applications in accordance with this feature.
But we should be aware of some hidden rock connected to VO's view criterias. When we apply any view critirias to a view object at run time, the framework checks whether there is any applied view criteria with the database query execution mode. And in such case the framework can not guaranty the consistency and it's going to switch the association consistency mode off at the view object level.
If we want to keep the mode working anyway, we have to set it up manually in the executeQueryForCollection VO's method:

protected void executeQueryForCollection(Object qc, Object[] params, 
         int noUserParams) {
  super.executeQueryForCollection(qc, params, noUserParams);

That's it!