Набор данных в Cache: коллекция была изменена; операция перечисления может не выполняться - PullRequest
1 голос
/ 25 марта 2011

Я храню набор данных в ASP.Net WebApplication-Cache.Каждый пользователь в этом интранет-приложении использует один и тот же экземпляр.При вставке / обновлении / удалении действий база данных будет обновлена, и набор данных будет соответствующим образом изменен.

Но редко я получаю исключение, которое указывает, что я что-то пропустил.Я предполагаю, что это должно быть как-то связано с безопасностью потоков.

 Collection was modified; enumeration operation might not execute

В строках, где я обращаюсь к DataTable в наборе данных, например:

Dim view As New DataView(dsERP.ERP_Charge, filter, sort, _
    Data.DataViewRowState.CurrentRows)

Очевидно, он был изменендругой поток, пока представление перечисляет данные.

Каков наилучший способ сделать этот поток безопасным?

Редактировать : как вы упомянули, мне нужно заблокировать объекты при операциях добавления / редактирования / удаления. MSDN * говорит, что DataSet является поточно-ориентированным для нескольких пользователей.Что это означает, являются ли DataTables в наборе данных также поточно-ориентированными?И как заблокировать один элемент данных для операций записи, а не весь набор данных?

* ADO.NET - многопоточное программирование

ADO.NET оптимизирован для производительности, пропускной способности и масштабируемости.В результате объекты ADO.NET не блокируют ресурсы и должны использоваться только в одном потоке.Единственным исключением является DataSet, который является поточно-ориентированным для нескольких читателей.Однако вам нужно заблокировать DataSet во время записи .

Это свойство, которое возвращает набор данных:

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

Благодаря casperOne, который я изменилОперации вставки / обновления и удаления выполняются следующим образом (dsRma - набор данных):

Dim success As Boolean
SyncLock dsRMA.RMA
     success = insert()
End SyncLock

Во-первых, работает ли это сейчас, если другой поток пытается перечислить таблицу RMA?Во-вторых, достаточно ли заблокировать обновляемый данные, а не блокировать все данные (см. Ниже)?

Dim thisRMA As ERPModel.dsRMA.RMARow = dsRMA.RMA.FindByIdRMA(Me.IdRma)
Dim success As Boolean
SyncLock thisRMA
       success = update(thisRMA)
End SyncLock

1 Ответ

1 голос
/ 25 марта 2011

Как правило, при перечислении по последовательности вы не можете выполнять операции, которые изменят последовательность.

Поскольку вы сохраняете коллекцию в кэше WebApplication, она может быть обработана несколькими потоками одновременно; у вас может быть запрос в одном потоке ввести элемент в кеш, в то время как другой пытается перечислить его.

Чтобы бороться с этим, вы действительно должны сделать доступ к структуре данных поточно-ориентированным.

У вас есть несколько вариантов для этого. Первым и самым простым будет инкапсулировать доступ к последовательности в блоке lock. Вы должны обернуть операции добавления / редактирования / удаления в отдельные блоки, и у вас также должен быть целевой тот же объект в блоке lock по перечислению последовательности всей .

Это может быть легко инкапсулировано в другом классе, а затем вы сохраните его в своем кэше.

Если вы также выполняете большое количество операций чтения по сравнению с операциями записи, то вы можете использовать класс ReaderWriterLockSlim для соответствующей блокировки чтения и записи; Приведенная выше стратегия заблокирует два одновременных чтения.

Другим решением будет блокировка любой операции добавления / редактирования / обновления в кэше, а когда вы хотите перечислить кэш, заблокируйте и создайте копию самой последовательности и верните ее; как только вы вернете копию последовательности, вы можете перечислить ее отдельно, поскольку эта последовательность отличается от той, которую вы на самом деле модифицируете.

...