Entity Framework - how to cache and share read-only objects
<p>We have an application with a fairly complex entity model where high-performance and low-latency are essential but we have no need for horizontal scalability.  The application has a number of event sources in addition to a self-hosted ASP.NET Web API 2.  We use Entity Framework 6 to map from POCO classes to the database (we use the excellent  <a href="https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838" rel="nofollow noreferrer" title="Reverse POCO Generator">Reverse POCO Generator</a> to generate our classes).</p>

<p>Whenever an event arrives the application has to make some adjustment to the entity model and persist this delta adjustment to the database via EF.  At the same time read or update requests may arrive via the Web API.</p>

<p>Because the model involves many tables and FK relationships, and reacting to an event usually requires all relationships under the subject entity to be loaded, we have elected to maintain the entire set of data in an in-memory cache rather than load the entire object graph for each event.  The image below shows a simplified version of our model:-</p>

<p><a href="https://i.stack.imgur.com/yQeVo.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yQeVo.png" alt="enter image description here"></a></p>

<p>At program start-up we load all the interesting <code>ClassA</code> instances (and their associated dependency graph) via a temporary <code>DbContext</code> and insert into a Dictionary (ie our cache).  When an event arrives we find the ClassA instance in our cache and attach it to a per-event <code>DbContext</code> via <code>DbSet.Attach()</code>. The program is written using the await-async pattern throughout and multiple events can be processed at the same time.  We protect the cached objects from being accessed concurrently by the use of locks so we guarantee that a cached <code>ClassA</code> can be loaded into a <code>DbContext</code> only one-at-a-time.  So far so good, the performance is excellent and we are happy with the mechanism.  <strong>But there is a problem</strong>.  Although the entity graph is fairly self-contained under <code>ClassA</code>, there are some POCO classes representing what we consider to be read-only static-data (shaded in orange in the image).  We have found that EF sometimes complains </p>

<blockquote>
  <p>An entity object cannot be referenced by multiple instances of IEntityChangeTracker.</p>
</blockquote>

<p>when we attempt to <code>Attach()</code> two different instances of <code>ClassA</code> at the same time (even though we are attaching to different <code>Dbcontexts</code>) because they share a reference to the same <code>ClassAType</code>.  This is demonstrated by the code snippet below:-</p>

<pre><code>    ConcurrentDictionary&lt;int,ClassA&gt; theCache = null;

    using(var ctx = new MyDbContext())
    {
        var classAs = ctx.ClassAs
            .Include(a =&gt; a.ClassAType)
            .ToList();

        theCache = new ConcurrentDictionary&lt;int,ClassA&gt;(classAs.ToDictionary(a =&gt; a.ID));
    }

    // take 2 different instances of ClassA that refer to the same ClassAType
    // and load them into separate DbContexts   

    var ctx1 = new MyDbContext();
    ctx1.ClassAs.Attach(theCache[1]);

    var ctx2 = new MyDbContext();
    ctx2.ClassAs.Attach(theCache[2]); // exception thrown here
</code></pre>

<p>Is there any way to inform EF that <code>ClassAType</code> is read-only/static and we don't want it to ensure that each instance can be loaded into only one <code>DbContext</code>?  So far the only way around the problem I've found is to modify the POCO generator to ignore these FK relationships, so they are not part of the entity model.  But this complicates the programming because there are processing methods in <code>ClassA</code> which need access to the static data.</p>