This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
Re: Collection Caching, the Caching page mentions, "If you wish to cache an entire entity set in memory (e.g. for reference data) you can use FindAll caching. To apply this to an entity open the LightSpeed Model Explorer (View > Other Windows > LightSpeed Model) and in the tree view locate the entity that you want to cache. Right-click it and choose Add New Caching Options. Then expand the entity, select the Caching Options node, and you will see the option for Cache Find All Result in the Properties grid." Is this basically an eager-loading/hydrating an entire entity load graph? Does FindAll have to be used?! If, for example, I have a Person entity which has a collection of Address entities, are those Addresses all cached (or is this a normal cache feature and wouldn't require Collection Caching). Another example. Let's say I have an entity called "Country" (arguably reference data that never changes) and I call something like:
Will that add all Countries into Level 2 cache on its first hit, loading from Level 2 cache on subsequent hits? Is Collection Caching necessary in this case? |
|
|
FindAll caching saves the database call to load the entities only to find each one of them exists in the L1/L2 cache after processing the result. If you are dealing with reference data which you know is not going to change in the cache lifetime you would want to use collection caching to avoid any subsequent database calls.
|
|
|
So must I use ".FindAll"? And how is this different from :
adding to the L2 cache on access? I guess I don't understand the point of Collection Caching if the above code would cache all Countries anyway... At what point does the Collection Cache get populated? Please let me know if the below is true? In my example, with Collection Caching off:
With Collection Caching on:
|
|
|
It will avoid the database call if you call FindAll again.
Point 2 is incorrect, it will not immediate check for entities in the L2 cache since it doesnt know the set of entities to check for, so a database call will be made and on hydrating the entities the cache is checked for an existing instance first. Using the collection caching avoids this call as we cache the set itself to know who the members are.
|
|
|
I'm trying really hard to understand this... First you mention that "[With Collection Caching on] a database call will be made and on hydrating the entities the cache is checked for an existing instance first," but then your next sentence you mention, "Using the collection caching avoids this call." Also, I need to know, must I use ".FindAll" or is uow.Countries equivalent? |
|
|
I performed some more testing and something appears to be very wrong... Setup: The "Property" and "LineItem" entities have Caching enabled. Example 1 (Collection Caching Off, Caching Doesn't Seem To Be Working):
each uow.LineItems... call generates a database call, which I expect because it's technically a "query" and not a "FindById I can see that all 4 items are added to the cache (Note, each LineItem has exactly one Property in the Property collection):
Therefore, it would seem that caching is not retrieving hydrated entities properly... Setup: The "Property" and "LineItem" entities still have Caching enabled. "LineItem" now also has Collection Caching enabled. Example 2 (Collection Caching Off, Caching Doesn't seem to be working, using the exact same code above):
In this example, each uow.LineItems... call generates a database call, which I still expect because it's technically a "query" and not a "FindById
performs a database call only on the first run and seems to populate the single Property for the LineItem (and retrieves p1 from cache for each additional call), however, LightSpeed seems to think a FindAll call has populated the entire Property collection, so when this line runs:
it DOES NOT perform a database call, AND p2 contains zero results (again, LightSpeed seems to be checking the FindAll Property cache and since it only contained one Property for l1, it returns zero results for p2.)
Therefore, caching does not appear to be working, or I am using it improperly, but I expect already hydrated entities, known to be in cache, to be retrieved first. Additionally, Collection Caching dangerously omits the "All" part of "Find All" when initially populated. Example 3: Even if I modify my code to use FindById
The initial calls to uow.FindById... do perform a database query and populate the cache as expected, and all subsequent calls to the same code above DOES pull each LineItem from cache immediately, again, as expected, however, EVERY call for properties performs a database query... instead of loading the fully populated LineItem entities from cache (which should include fully populated collections of Properties)... Per Caching,
This does not appear to be the case:
|
|
|
Hi Bill, I think the main issue in both of these examples is you are expecting the Properties collection on each LineItem which is being returned from the second level (L2) cache to be populated because when they were originally cached those collections were populated at the time - is that correct? If so the reason this is not occurring is that we dont cache the child collection information for entries in the L2 cache. To expand on this Im assuming by cache in the examples you mean the L2 cache. With the L2 cache only the entity instance itself is cached and any child collections are marked as lazy so they will trigger a database call on the next access. If the collection of properties are known and are cached (so you can fetch them by Id) you can manually load the child collections which would avoid the DB call. Im not clear from your examples if this is achievable or sensible but if it is you may want to load these manually. The best way to do this is by implementing a custom method on your entity class which allows you to assign a set of values into that collection. As a bit of background on this under the covers child collections are managed within a managed container called an EntityCollection (you will see an EntityCollection used for holding the children on your association). This in turn has a flag indicating if the collection is loaded. So ultimately what we want to do is indicate that the collection is already loaded prior to you accessing it via its standard collection property which would otherwise trigger a lazy load to occur. This flag is exposed but it needs to be accessed directly against the field on the entity itself as touching the collection would trigger a lazy load, so to do this we could set up a method such as:
|
|