Telerik blogs

OpenAccess provides you not only with one, but two caches for persistent objects.

The first level cache is the cache that directly supports the IObjectScope and that is responsible for the uniqueing of database references. That means, it is responsible to assure that there is only one physical instance per logical database entity: Equal foreign key reference values lead to a consistent representation in memory so that no duplicate representation of a single database row exists within an IObjectScope. This cache also holds the modified objects in a scope. The first level cache is always present and there is a 1:1 relationship between IObjectScope and first level cache.

 

The second level cache is a different beast. It is shared between all object scopes of an AppDomain that connect to the same database. In essence, it is a map of object identifiers (keys) to object data (values). In addition to that map there is a second, separately configurable map of queries with their parameters (keys) to object identifiers (values).

What the second level cache is intended for is to provide a caching database view so that queries or object identifiers can be resolved quickly on the client without touching the database server at all. The cache is populated by unresolved read requests: whenever a data is missing and the database server is contacted, the returned data is inserted into the cache too; the cache is limited in it's size and will replace entries based on a LRU policy.

 

The second level cache can be configured in the backendconfiguration section of the config file. It can also be controlled programmatically through the DatabaseLevelCache class obtainable from the Cache property of the database instance. At the moment, two operations on the database level cache are possible: eviction and information.

With the Evict() methods it is possible to remove entries from the cache, and with the IsCached(IObjectId) method it is possible to know if the values for a certain object are cached.
The eviction can be useful in scenarios, where the content of the database is modified by other means than OpenAccess (direct SQL usage), so that the cache must no longer hold the old data.

 

You have to be aware, that only the content of the second level cache is altered by this API. The data that was already fetched into the first level cache must also be invalidated, when needed.

Let's have a look onto a small example that shows the API in action. The code assumes, that the database content is changed in the middle of the code manually.

 

using System;
using Telerik.OpenAccess;

namespace CacheEviction
{
   
class Program
   
{
       
static void Main(string[] args)
       
{
           
Database db = Database.Get("DatabaseConnection1");

           
using (IObjectScope s1 = db.GetObjectScope())
           
{
               
// let's store some data
                MyData d = new MyData();
               
d.MyValue = "OLD";
               
s1.Transaction.Begin();
               
s1.Add(d);
               
s1.Transaction.Commit();

               
// transaction begin forces a reload of the first level cache
                // when needed
                s1.Transaction.Begin();
                
               
// next line populates the second level cache as well as the
                // first level cache
                string old = d.MyValue;

               
// assuming the database content was changed now independend of this code

               
// let's evict the content of this object out of the cache.
                s1.Database.Cache.Evict(s1.GetObjectId(d));
                
               
// the new database content will be delivered now from the l2 cache.
                // but for that content to be visible here, we need to refresh
                // the first level cache too!
                s1.Refresh(d);

               
// now we access the refreshed value
                string freshFetch = d.MyValue;
               
s1.Transaction.Rollback();
           
}
       
}
   
}

   
[Persistent]
   
public class MyData
   
{
       
private string myValue;
       
[FieldAlias("myValue")]
       
public string MyValue
       
{
           
get { return myValue; }
           
set { myValue = value; }
       
}
   
}
}


 


Colorized by: CarlosAg.CodeColorizer

Comments

Comments are disabled in preview mode.