Showing posts with label View Accessors. Show all posts
Showing posts with label View Accessors. Show all posts

16 Aug 2014

Entity Level View Accessors

The sign on the View Accessors tab in JDeveloper says "View accessors are used for defining and filtering the data source referenced in list based validation and presented in a list of values". And really, usually we define view accessors for LOVs and, may be, sometimes, for list validators. But besides that view accessors can be used as a convenient way to execute a SQL query while implementing some business logic. Since business logic is concentrated at the entity level and usually is implemented in the EntityImpl class it is convenient to define and work with a view accessor at the entity level.
Let's consider a simple use case. There is a standard Employees entity. In order to implement some business logic we need to calculate an average salary for the employee's job in the employee's department. So, we need to execute the following SQL query:

select AVG(Salary) avg_salary 
from Employees 
where department_id = :departmentid and
      job_id = :jobid

We have defined a view object based on this query (just definition without any instance in AM) and defined a corresponding view accessor in the Employees entity:


For the view objects like this, that are used for some calculations only, it is recommended to setup Forward Only access mode at the Tuning section of the General tab:



JDeveloper generated a getter method for the view accessor in the EmployeesImpl class:
/**
 * Gets the view accessor <code>RowSet</code> VAVGSalary.
 */
public RowSet getVAVGSalary() {
    return (RowSet) getAttributeInternal(VAVGSALARY);
}


And whenever we need to get an updated result of this query in our Java code we can do tho following:

public BigDecimal getCalcAvgSalary() {
    Row r  = getVAVGSalary().first();
    return (r!=null ? (BigDecimal) r.getAttribute(0) : null);         
}
 
This method can be used in a Groovy expression as well. For example as a default value expression of some transient attribute:

That's it!

27 May 2014

Entity Level View Accessors

In one of my previous posts I explained what happens behind the scene while working with View Accessors. Usually we define view accessors in the same view object definition where we define lists of values. However, it is also possible to define view accessors at the entity definition level. In that case we can use an entity level view accessor when defining lists of values in the entity based view objects. This is a pretty convenient feature in terms of reusing. So, a proper view accessor  can be defined only once at the entity definition level and it’s going to be available for reusing in all view objects that are based on this entity definition.
But besides convenience, this feature can also be useful in terms of performance. For each view accessor definition the framework at runtime creates an internal lookup VO instance according to the view definition linked to the view accessor. This is shown on the following diagram.


There are two VO definitions on the diagram - VO1 and VO2. Both of them are based on the same entity definition. There are three view accessors on the diagram. Two of them are defined at the view object definition level and the rest one is defined at the entity definition level. All view accessors point to the same lookup view object definition. The framework at runtime is going to create three internal view object instances. One instance per view accessor definition. Note, that lists of values that are based on the entity level view accessor will share the same lookup view object instance, which means they are going to reuse the same query results and share the same query collection cache.
So, view accessors, defined at the entity level can be considered by ADF developers as a promising technique.


That's it!

28 Feb 2014

Understanding View Accessors

Introduction
In an ADF application a view accessor is considered as an approach to access a view object from another view object or entity object. The view accessors are mostly used to provide result sets for the lists of values. In this post I am going to show how actually the view accessors work, to reveal what's going on behind the scene, to clarify how many internal view object instances are created by the framework and how many row sets are used.


Internal View Object instances
Let's start with easy things. I've got a view object definition VForexTrade representing forex operations on the currency market. It has an attribute Buycurrencyid with a list of values LOV_Buycurrencyid:


It also has an attribute Sellcurrencyid with a list of values LOV_Sellcurrencyid:



There is a view accessor VCurrency1 which is based on VCurrency view definition.

So there are two LOVs referring to the same view accessor.

And there is an application module TestAppModule with an instance of VForexTrade view object definition. The name of this instance is VTodTrade and it represents today trade operations:



This simple structure can be represented in the following table:
VO instance LOV attribute VA VA View definition Shared VO instance Row Level Binds
VTodTrade Buycurrencyid VCurrency1 VCurrency - true
VTodTrade Sellcurrencyid VCurrency1 VCurrency - true


Since VCurrency1 view accessor doesn't use any shared VO instance, the framework, at run time, is going to create an internal view object instance basing on VCurrency view definition. In this case its name will be like _LOCAL_VIEW_USAGE_VForexTrade_VCurrency1. Note that the name is constructed as a concatenation of view definition names. The VO instance name doesn't matter.

Since the RowLevelBinds property of the view accessor is set to true, the framework, at run time, is going to create a separate non-default row set for each row of the VTodTrade instance. So, the internal view object instance will have a number of row sets like _LOCAL_VIEW_USAGE_VForexTrade_VCurrency1_0, _LOCAL_VIEW_USAGE_VForexTrade_VCurrency1_1,
_LOCAL_VIEW_USAGE_VForexTrade_VCurrency1_2, ...

So, each row in the VTodTrade refers to its own row set providing a list of currencies. But since this list of currencies doesn't really depend on a VTodTrade's row, and VCurrency VO doesn't have any bind variables, all these row sets are backed up by the same query collection. By the first one _LOCAL_VIEW_USAGE_VForexTrade_VCurrency1_0.  That means that the VCurrency's SQL query will be executed only once.  



Let's change this structure a little bit defining a separate view accessor VCurrency2 for the LOV_Sellcurrencyid list of values.
VO instance LOV attribute VA VA View definition Shared VO instance Row Level Binds
VTodTrade Buycurrencyid VCurrency1 VCurrency - true
VTodTrade Sellcurrencyid VCurrency2 VCurrency - true

In this case, at run time, the framework will create another internal VO instance _LOCAL_VIEW_USAGE_VForexTrade_VCurrency2 for the VCurrency2 view accessor. This instance is going to have its own bunch of row sets _LOCAL_VIEW_USAGE_VForexTrade_VCurrency2_0,
_LOCAL_VIEW_USAGE_VForexTrade_VCurrency2_1,
_LOCAL_VIEW_USAGE_VForexTrade_VCurrency2_2, ... .
All of them are going to be backed up the _LOCAL_VIEW_USAGE_VForexTrade_VCurrency2_0 query collection.



So, here we'll have two executions of the VCurrency's SQL query for both query collections.

Let's switch off  the RowLevelBinds property of our view accessors:
VO instance LOV attribute VA VA View definition Shared VO instance Row Level Binds
VTodTrade Buycurrencyid VCurrency1 VCurrency - false
VTodTrade Sellcurrencyid VCurrency2 VCurrency - false

In this case the framework will also create two internal VO instances _LOCAL_VIEW_USAGE_VForexTrade_VCurrency1 and _LOCAL_VIEW_USAGE_VForexTrade_VCurrency2. But each of them will have only one default row set to be shared across all rows of the VTodTrade view object instance. However, the VCurrency's SQL query will be executed twice, since each internal VO is going to be backed up by its own query collection.


Alrighty, let's add one more instance of the VForexTrade to the application module.



Our BC model is represented in the following table:
VO instance LOV attribute VA VA View definition Shared VO instance Row Level Binds
VTodTrade Buycurrencyid VCurrency1 VCurrency - false
VTodTrade Sellcurrencyid VCurrency2 VCurrency - false
VForwardTrade Buycurrencyid VCurrency1 VCurrency - false
VForwardTrade Sellcurrencyid VCurrency2 VCurrency - false

The interesting thing is that nothing is going to be changed, actually. The framework will create the same two internal view object instances with default row sets for each VA definition, and they will be shared by both VTodTrade and VForwardTrade VO instances.






Shared View Object instances

And now let's redefine our view accessors and get them referring to a shared VO instance.
VO instance LOV attribute VA VA View definition Shared VO instance Row Level Binds
VTodTrade Buycurrencyid SharedModule_VCurrency1 VCurrency VCurrency true
VTodTrade Sellcurrencyid SharedModule_VCurrency2 VCurrency VCurrency true

Since the view accessors refers to a real VO instance from some shared AM, the framework won't create any additional internal view objects. Instead of that, it will create a non-default row set within VCurrency shared VO for each view accessor usage with RowLevelBind set to true. And again, there is no any bind variables in the VCurrency and its result set doesn't depend on a row from which it is used. So, all these created row sets are going to be backed up by a single query collection instance. The behavior is pretty similar for both session and application shared AMs. The difference is that in the case of the session shared AM there will be one VCurrency instance per user session, and in the case of the application shared AM the framework will create only one single instance of VCurreny to be shared across the entire application. Besides that, the query collection of a session shared VO can be destroyed due to the AM recycling process or because of the garbage collection process. That will not happen with an application shared VO instance. There is a different mechanism to clean up query collections of the application shared view objects.



 
If we set the RowLevelBind property to false
VO instance LOV attribute VA VA View definition Shared VO instance Row Level Binds
VTodTrade Buycurrencyid SharedModule_VCurrency1 VCurrency VCurrency false
VTodTrade Sellcurrencyid SharedModule_VCurrency2 VCurrency VCurrency false

The framework will create a single default row set for the VCurrency view object, and this row set is
going to be shared for each view accessor usage across all rows.



That's it!

God Save Ukraine!