Dear App Experts,
I am currently trying to find out how exactly the data loading works in Apps to better design our Apps.
It seems to me, that all queries, no matter whether in the datasource or in the element are handed through to the database.
E.g. I have tried to have 2 elements on a page (each with a different query) that share the same datasource. What I can see is, that there are 2 calls “RetrieveData” happening, one for each element, even though they share the same datasource.
It would be just the same if I had 2 datasources, both pointing to the same data, right? Is there any difference to whether I put my query in the datasource or into the element? And how is the data then cached in the app? Is it once per datasource? Or is it once per element?
Would also be happy if you could point me to any documentation regarding this (I could only find an article about Syncsets).
Edit: So far I have only looked at behaviour for Postgres tables in case that is relevant.
tldr: caching is per element
Data is loaded like this:
- Elements call a high-level method that fetches data and prepares it in a way convenient for the type of element (e.g. table, chart, etc.)
- All these high level methods delegate to a lower level method that does the actual fetching of data
- Before fetching data, a client-side cache is checked for a hit
- the cache key contains this:
- transformations (e.g. filters, sorting, sql)
- If there is no cache hit or the cache was actively invalidated (e.g. if there was an update to the datasource or data was edited in the app), the data is fetched
It’s even more complicated than this as we try to also hit the cache for requests that are “in flight”, e.g. don’t have a result yet, and also try to avoid race conditions caused by requests “overtaking” each other. But the sequence above should give you a better idea of what happens behind the scences.
For the caching behavior, it makes no difference if you put transformations in the datasource or element as all transformations are bundled together anyway. Only their order might change (as datasource-transformations are applied before sync set filters and before element transformations, user defined filters and sorting)
Thanks a lot for the answer, that clears up a lot for me
Just out of interest, you say that the cache key contains not just the elementId but also transformations, etc. - isn’t the elementId the “smallest shared entity” (I mean “kleinster gemeinsamer Nenner”) in the sense that it specifies something uniquely? I mean could there be 2 entries that have the same elementID but different transformations? Or is this for supporting data loading properly also during App Development?
If the cache key would not vary on transformations, we would hit the cache even when, for example, the user changes a filter or a variable change results in a changed sql-transformation on the element.
As there are so many events that could result in a change of the transformations, it would be hard to actively invalidate an element-keyed cache, so we just pull everything into the cache key.
A nice side effect is that switching back and forth between transformations also results in cache hits. So if a user switches a filter on and off or toggles sorting from asc to desc and back, we still have the data cached. If the cache would be keyed by the elementId only, we would have overwritten the cache with the new data.
A not so nice side effect of this is that this is essentially a memory leak as we never clean the cache as long as the user stays in the app and there’s no update coming in for one of the datasets.
Of course, I haven’t thought far enough - thanks for the explanation!