title: Dataset in Cache: Collection was modified; enumeration operation might not execute
body: <p>I'm storing a dataset in an ASP.Net WebApplication-Cache. Every user in this intranet-app uses the same instance. On insert/update/delete-actions the database will be updated and the dataset is modified accordingly.</p>
  
  <p>But rarely I get an exception that indicates that I've missed something. I assume that it must have something to do with thread safety.</p>
  
  <pre><code> Collection was modified; enumeration operation might not execute
  </code></pre>
  
  <p>In lines where i access a DataTable in the Dataset, for example: </p>
  
  <pre><code>Dim view As New DataView(dsERP.ERP_Charge, filter, sort, _
      Data.DataViewRowState.CurrentRows)
  </code></pre>
  
  <p>It was apparently changed by another thread while the view enumerates the datatable. </p>
  
  <p>What is the best way to make this thread safe?</p>
  
  <p><strong>Edit</strong>: as you've mentioned i need to lock the objects on add/edit/delete operations.
  <a href="http://msdn.microsoft.com/en-us/library/ms971481.aspx" rel="nofollow">MSDN</a>* says that a DataSet is thread-safe for multiple users. What does this mean, are the DataTables in the Dataset also thread-safe? And how to lock a single datatable on write-operations and not the whole dataset? </p>
  
  <blockquote>
    <p>*<strong>ADO.NET - Multithreaded Programming</strong></p>
    
    <p>ADO.NET is optimized for performance, throughput, and scalability. As a result, the 
    ADO.NET objects do not lock resources and must only be used on a single thread. The one
    exception is the DataSet, which is thread-safe for multiple readers. However, you need 
    lock the DataSet during <strong>writes</strong>.</p>
  </blockquote>
  
  <p>This is the property that returns the dataset:</p>
  
  <pre><code>Public ReadOnly Property dsERP() As ERPModel.dsERP
      Get
          If Cache("DS_ERP") Is Nothing Then
              Cache("DS_ERP") = New ERPModel.dsERP
              FillDataSet()
          End If
          Return DirectCast(Cache("DS_ERP"), ERPModel.dsERP)
      End Get
  End Property
  </code></pre>
  
  <p>Thanks to casperOne i've modified the insert/update and delete operations in the following way(dsRma is a dataset):</p>
  
  <pre><code>Dim success As Boolean
  SyncLock dsRMA.RMA
       success = insert()
  End SyncLock
  </code></pre>
  
  <p>First, does it work now if another thread tries to enumerate the RMA-Table? Second, is it sufficient to lock the datarow that gets updated instead of locking the whole datatable(see below)?</p>
  
  <pre><code>Dim thisRMA As ERPModel.dsRMA.RMARow = dsRMA.RMA.FindByIdRMA(Me.IdRma)
  Dim success As Boolean
  SyncLock thisRMA
         success = update(thisRMA)
  End SyncLock
  </code></pre>