title: ConcurrentDictionary.GetOrAdd when valueFactory has side-effects
body: <p>I'm trying to offload work from my database server by introducing a cache layer for some very central functions that insert a value to a table in the database and retrieves the id. This is in a multi-threaded environment.</p>
  
  <p>My first approach was:</p>
  
  <pre><code>public class Cache {
        private Dictionary&lt;string, Int64&gt; i;
  
        public void Init() { /* init i with values from DB */ }
  
        public Int64 Get(string value)
           lock(i) {
              Int64 id;
              if (cache.i.TryGetValue(value, out id))
                  return id;
  
              id = /* Insert to DB and retrieve ID */
              cache.i[value] = id;
              return id;
        }
   }
  </code></pre>
  
  <p>This helped. However the threads still wait a lot for each other. I'd like to reduce this waiting time. My first thought was to use <code>ConcurrentDictionary.GetOrAdd(key, valueFactory)</code>. This would not work because valueFactory could be called more than once.</p>
  
  <p>I've wound up at this approach:  </p>
  
  <pre><code>public class Cache
  {
      private ConcurrentDictionary&lt;string, Int64&gt; i;
  
      public void Init() { /* init i with values from DB */ }
  
      public Int64 Get(string value)
      {
          Int64 id;
          if (i.TryGetValue(value, out id))
              return id;
  
          lock (i)
          {
              if (i.TryGetValue(value, out id))
                  return id;
  
              id = /* Insert to DB and retrieve ID */
              i.TryAdd(value, id);
              return id;
          }
      }
  </code></pre>
  
  <p>Is there a better way of doing this? Is this even thread-safe?</p>