Cached classes
Definition | Creation of cached classes | Access to cached values | Code example |
1. Definition
In application programs, it is necessary to have quick access to the tables where miscellaneous values that manage parameters or options are stored. You can do this through general parameters using the ACACHE
child instance in the context.
Also, it is sometimes necessary to get data stored in cache for other parameter tables with a key value, such as currency tables that are accessed frequently.
The cached classes are intended to implement a quick access to cache stored data. The access to cached classes will also be done from an instance of a child class of the context.
Cache classes are dedicated to store in the context values of "small" parameter tables such as currencies, units, language codes...
When such a class exists, the data from the corresponding table will be lazy loaded for every line that is requested.
This is of course only usable on the following conditions:
* It must be a table that handles a "small" number of lines, or at least on which only some lines are usually loaded for a given session.
* The data stored in this table must be "stable" enough. If a record changes, the session already running and storing the previous value of data will continue to use the previous value that remains in cache until the session is restarted.
2. Creation of cached classes
Creating a cached class requires two steps:
1. Declare a class that stores the cached value. This class has the following constraints:
* It cannot contain a collection.
* It should contain only a restricted list of properties.
* It can only be a persistent or an interface type Class.
* It cannot be the same class as the ones managing the CRUD on the table because a buffer Class is read-only. It does not support accessors (control and propagate), nor have other methods than AREAD
, and nor manage other events than AREAD
(if interface) and AREAD_BEFORE
, AREAD_AFTER
(if persistent).
2. Re-validate the context in the context definition .
You need to give for your cached class another name than the usual class name. For instance, to consider the currencies stored in the TABCUR
table:
- Managing the currencies in CRUD mode is usually be done through a
TABCUR
class. - Managing the cached values associated with currencies must be done with another name, for instance
ACUR
class.
3. Access to cached values
In the current context, ACACHE
is the property that provides access to the different cache instances. If we consider the ACUR
cache class defined in the example above, ACACHE.ACUR.ACOL
is an array of instances of the ACUR
class storing the cached values for the currency data. ACACHE.ACUR
is an instance of an intermediate class that provides the following methods:
AGETINDEX(KEYS)
: Returns the index of the cached instance for the corresponding key values. If the value is not read, this method performs the read. If no record exists for the given key value, this method returns[V]CST_ANOTDEFINED
.KEYS
is a list of parameters corresponding to the values of the different key segments.AGETVALCHAR(KEYS,"PROPERTY_NAME")
: Returns a character type property.AGETVALNUM(KEYS,"PROPERTY_NAME")
: Returns a integer type property.AGETVALDEC(KEYS,"PROPERTY_NAME")
: Returns a decimal type property.AGETVALDAT(KEYS,"PROPERTY_NAME")
: Returns a date type property.
It is also possible to use ACACHE.ACUR.ACOL(index).PROPERTY
to access to a property once the index value has been found with the AGETINDEX
method.
4. Code example
ACUR
is a cached class that contains the following properties:
CUR
is the currency code and the key.CURRND
is the rounding parameter.EURFLG
is the European flag.EURDAT
is the European switch date.
Handling different currencies can be done based on the following example:
# Index in the cache structure
Local Integer CUR_NO
# Use in here a pointer declaration that will directly simplify the access to the cached values.
# Obviously, no New instance (and no Free instance !!!) will be done using this pointer.
# The memory allocation of the cache is done by the supervisor.
Local Instance CUR Using C_ACUR
# If the current currency is not euro (or if the euro switching date has not arrived), compute a value
# Get the index and verify that CUR_INDEX is ok
CUR_NO= Fmet this.ACTX.ACACHE.ACUR.AGETINDEX(this.MYCURRENCY)
If CUR_NO=[V]CST_ANOTDEFINED
# The currency does not exist, handle the error and exit
...
Endif
CUR=this.ACTX.ACACHE.ACUR.ACOL(CUR_NO)
# Perform a rounding on the AMOUNT property
If CUR.EURFLG=1 or CUR.EURDAT>date$
this.AMOUNT=arr(this.AMOUNT,CUR.CURRND)
Endif
A second example is given below with a cached class where the key has two components.
# To store some budget revision parameters, a cached class called 'BUV' has been created with the following properties:
# STA : Status (1=opened, 2=closed).
# DEF : Default value (1=no, 2=yes).
# BUD,VER : budget code, revision code (components of the key).
# this.MYBUDGET is the budget we need to control, and this.MYVERSION is the revision of the budget.
# Let's control if the budget is opened:
If Fmet this.ACTX.ACACHE.BUV.AGETVALNUM(this.MYBUDGET,this.MYVERSION,"STA")<>1
# Raise an error because the budget is closed (2). Might return 0 if budget does not exist
...
Endif
# Let's have a specific action if the budget is not the default one
If Fmet this.ACTX.ACACHE.BUV.AGETVALNUM(this.MYBUDGET,this.MYVERSION,"DEF")=1
# Specific action code
...
Endif