Servoy Tutorial: Using an Object as a Cache

Servoy Tutorial: Using an Object as a Cache

Servoy Tutorial Photo Credit: kenteegardin via Compfight

This is an object-oriented Servoy tutorial on how to use an object as a cache in Servoy. Using an object to cache data can solve a lot of coding challenges, as well as significantly boost the performance of your code. For example, it can be used to manage foundsets that a collection of methods will work with. Rather than loading a foundset over and over again in each method that is called, you can cache the foundset and retrieve it when you need it. You can also retrieve the entire foundset, not just the first 200 records (which is all that Servoy will load by default), as well as the total record count for the foundset. In addition, some methods you call could modify the foundset and store it back in the cache, ready for the next method that needs to work with the data, avoiding expensive databaseManager.saveData() calls. Other methods may be filtering the foundset, using omitRecord(), and hence by using a cache to retrieve the foundset, your methods are always working with all the right data.

Keep in mind that a cache can be used for more than just foundsets. You can extend it to store any kind of values by key. The cache can be setup when the main method initializes, taking a snapshot of the data at that point in time, so that all methods can access it. Later the cache can be cleared freeing the memory, ready for the next time when the process starts all over. All your objects storing your cached data, and any utility methods you create to work with the data, are all in one place, making your code elegant, highly maintainable, and easily extendable.

Here is an example of a single global cache object, with self managing methods, capable of storing an unlimited number of foundsets based on table name or any user defined key. We will walk through each part in this Servoy tutorial so you can see what is going on here.

We start out by creating an oCache object in our global.js file and an object in that called fs to store foundsets. We are going to store foundsets and the record count in these objects that we added to the oCache.fs object and identify them using a key. In our example, an object called ‘t_data’ has been added with two properties, fs and fsCount. This is the format we are going to use when we cache new foundsets and record counts by key.

The oCache object also has several utility methods that perform the following functions on the cache:

  • clearAll: Resets the entire oCache.fs object, dropping all the cached foundsets and freeing the memory.
  • fsGet: The main method that does the heavy lifting. This method checks to see if an object exists for the tablename, or optional key, passed to the method in the parameters. If not, it creates the base object, gets the foundset for the tablename, or uses an optional foundset that can also be passed to the method (like a related foundset), computes the record count for the foundset, and stores both the foundset and record count in the object. Before returning, the method duplicates the foundset (so the original copy is not affected by any method that calls the cache and manipulates the foundset), loads all the records into the foundset, and returns it to the caller. Retrieve a foundset from the cache using this method, and you get a copy that contains all the records, not just the first 200. This method could easily be modified to accept a boolean as a parameter, controlling whether or not you want a copy of the foundset, or the original (in case your method is going to modify the foundset and you need to pass the modified foundset to subsequent methods).
  • fsClear: This method can be used to clear a specific foundset by key.
  • fsReset: This method will clear a foundset by key, then call fsGet to reload the foundset, recompute the record count, and return the fully a copy of the entrire foundset.
  • fsSet: This method will set the foundset to an optional one you pass in(like a related foundset). It first calls fsClear and then fsGet, passing in the optional foundset.
  • fsCount: This method return the foundset count for the key, if it exists.

To use the global cache, you can do the following (assuming Servoy 7.3, otherwise drop the scope prefix):

This will create the foundset the first time it is called, and then reuse the cache until fsClear is called.

Getting the foundset record count for the loops is easy as well, using:

Finally, to clear the foundset from the cache and start over next time:

Using a cache has several advantages:

  • Avoid recomputing the foundset count in each method.
  • Ensure that each method uses the entire foundset.
  • Load the entire foundset only one time for all methods.
  • Pass a modified foundset from method to method.
  • Organize your cached data and utility methods in one place.
  • Code is highly maintainable and extendable.

Even if you don’t want to use a global cache object like I show here, at least use function memoization. This uses a local object in a function to build a cache and can improve the code performance, avoiding methods from calculating the same thing over and over again.

Bottom-line, use a cache, whenever and wherever you can; cache is definitely king when it comes to increasing code performance. It also helps you solve a number of technical problems, and keeps everything neatly organized in one place.

Gary Dotzlaw
Gary Dotzlaw has 20+ years of experience as a professional software developer and has worked with over 100 companies throughout the USA and Canada. Gary has extensive qualifications in all facets of the project life cycle, including initial feasibility analysis, conceptual design, technical design, development, implementation and deployment. Gary is an expert Servoy Developer, with extensive large-commercial project experience, and has written numerous advanced tutorials on Servoy development.