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