title: Parallel.ForEach and DbContext
body: <p>I'm using <code>Parallel.ForEach</code> and it's hugely improving the performance of my code, but I'm curious about <code>DbContext</code> with multiple threads. I know it's not thread safe so I'm using locks where I need to.</p>
  
  <p>The loop iterates over a dictionary and calculates statistics:</p>
  
  <pre><code>Dictionary&lt;string, List&lt;decimal&gt;&gt; decimalStats = new Dictionary&lt;string, List&lt;decimal&gt;&gt;(); // this gets populated in another irrelevant loop
  
  List&lt;ComparativeStatistic&gt; comparativeStats = db.ComparativeStatistics.ToList();
  var statLock = new object();
  
  Parallel.ForEach(decimalStats, entry =&gt;
  {
      List&lt;decimal&gt; vals = ((List&lt;decimal&gt;)entry.Value).ToList();
  
      if (vals.Count &gt; 0)
      {
          string[] ids = entry.Key.Split('#');
          int questionId = int.Parse(ids[0]);
          int yearId = int.Parse(ids[1]);
          int adjacentYearId = int.Parse(ids[2]);
  
          var stat = comparativeStats.Where(l =&gt; l.QuestionID == questionId &amp;&amp; l.YearID == yearId &amp;&amp; l.AdjacentYearID == adjacentYearId).FirstOrDefault();
  
          if (stat == null)
          {
              stat = new ComparativeStatistic();
              stat.QuestionnaireQuestionID = questionId;
              stat.FinancialYearID = yearId;
              stat.AdjacentFinancialYearID = adjacentYearId;
              stat.CurrencyID = currencyId;
              stat.IndustryID = industryId;
  
              lock (statLock) { db.ComparativeStatistics.Add(stat); }
          }
  
          stat.TimeStamp = DateTime.Now;
  
          decimal total = 0M;
          decimal? mean = null;
  
          foreach (var val in vals)
          {
              total += val;
          }
  
          mean = Decimal.Round((total / vals.Count), 2, MidpointRounding.AwayFromZero);
  
          stat.Mean = mean;
      }
  });
  
  db.SaveChanges();
  </code></pre>
  
  <p><strong>My question:</strong> Why do I only need the lock when I'm <em>adding</em> something to the database? If <code>stat</code> is never null - if there's always already a database entry for it - I can run this loop without a lock with no problems, and the database gets updated as intended. If <code>stat</code> is null for a particular loop and I don't have the lock there, a <code>System.AggregateException</code> gets thrown.</p>
  
  <p><strong>edit1:</strong> I've tried opening a new connection to the database each time instead of using <code>lock</code>, which also works when adding to the database (identical to the loop above, I've added comments where it differs):</p>
  
  <pre><code>Parallel.ForEach(decimalStats, entry =&gt;
  {
      List&lt;decimal&gt; vals = ((List&lt;decimal&gt;)entry.Value).ToList();
  
      if (vals.Count &gt; 0)
      {
          using (var dbThread = new PDBContext()) // new db connection
          {
              string[] ids = entry.Key.Split('#');
              int questionId = int.Parse(ids[0]);
              int yearId = int.Parse(ids[1]);
              int adjacentYearId = int.Parse(ids[2]);
  
              var stat = comparativeStats.Where(l =&gt; l.QuestionID == questionId &amp;&amp; l.YearID == yearId &amp;&amp; l.AdjacentYearID == adjacentYearId).FirstOrDefault();
  
              if (stat == null)
              {
                  stat = new ComparativeStatistic();
                  stat.QuestionnaireQuestionID = questionId;
                  stat.FinancialYearID = yearId;
                  stat.AdjacentFinancialYearID = adjacentYearId;
                  stat.CurrencyID = currencyId;
                  stat.IndustryID = industryId;
  
                  dbThread.ComparativeStatistics.Add(stat); // no need for a lock
              }
  
              stat.TimeStamp = DateTime.Now;
  
              decimal total = 0M;
              decimal? mean = null;
  
              foreach (var val in vals)
              {
                  total += val;
              }
  
              mean = Decimal.Round((total / vals.Count), 2, MidpointRounding.AwayFromZero);
  
              stat.Mean = mean;
  
              dbThread.SaveChanges(); // save
          }
      }
  });
  </code></pre>
  
  <p>Is this safe to do? I'm sure Entity Framework's connection pooling is smart enough but I'm wondering if I should add any parameters to limit the number of threads/connections.</p>