All OpenAccessContext instances from the same database can share a secondary cache. This cache is generally called "2nd level cache" or "L2 cache". The L2 cache holds copies of the database content of application objects. That means that the values for the various fields of the user object (like a Person instance) are duplicated in the L2 cache. The cache is populated during read access and gives fast retrieval of commonly used objects. The cache resides in the application process and the cache content is indexed by the object id. Additionally, the cache can contain complete query results. The query string and the parameters are used to index the results.
The 2nd level cache is designed to implement a multithreaded application, where, every single thread has its own context. In order to, avoid too many calls to the relational server, Telerik Data Access has a caching mechanism, the 2nd level cache, which is shared by all contexts in a single process. This is optimal if you implement a Web Application, which typically has a thread pooling and opens a new context for all incoming calls. Here, database access is necessary only when the data, which needs to be retrieved is not currently available in the cache, thereby increasing the efficiency and performance of your application.
When an object is updated by thread A, it is true that it is evicted from the L2 cache. However, if you have that object loaded in thread B, you are not seeing the new data immediately after the evict. The objects could be refreshed in two ways and this behavior is valid disregarding if L2 cache is on or off. When a context calls SaveChanges or ClearChanges, all the objects that have been loaded by that context are put into a NotLoaded state. This means they will be refreshed next time they are accessed for read/write. The refreshed state is obtained from the L2 cache if the object has not been changed by another thread, otherwise it is fetched the database. If thread B knows about the objects that are changed by thread A(maybe you have some custom logic for that), you can explicitly call Refresh() on the objects that are being changed and get the latest data for them without calling SaveChanges() on the context in thread B.
The 2nd level cache is used to avoid database access for non-transactional reads and reads in optimistic transactions. It is bypassed for datastore transactions to ensure that database locks are obtained. Only data read in an optimistic transaction or outside of a transaction are cached. Data for individual instances and the results of queries are cached.