У нас есть сетка, привязанная к List<T>
элементам. Всякий раз, когда пользователь нажимает «Обновить», изменения извлекаются из базы данных, и связанный список обновляется. Я столкнулся с проблемой, когда в сетку добавляются повторяющиеся элементы, и я не могу понять, почему.
Вызов базы данных возвращает два значения: List<int>
идентификаторов записей, которые изменились, и List<MyClass>
обновленных данных для измененных записей. Существующий код, который я отлаживаю, который определяет, что нужно обновить, выглядит примерно так:
public void FindUpdates(IList<MyClass> existingRecords,
IList<MyClass> updatedRecords,
List<int> updatedIds,
out IDictionary<int, int> existing,
out IDictionary<int, int> updated,
out List<int> updates,
out List<int> removes,
out List<int> adds)
{
updates = new List<int>();
removes = new List<int>();
adds = new List<int>();
existing = FindUpdated(existingRecords, updatedIds);
updated = FindUpdated(updatedRecords, updatedIds);
if (updatedIds != null)
{
// split add/update and remove
foreach (int id in updatedIds)
{
if (!existing.ContainsKey(id))
adds.Add(id);
else if (updated.ContainsKey(id))
updates.Add(id);
else
removes.Add(id);
}
WriteToLog(updatedIds, adds, updates, removes);
}
}
private IDictionary<int, int> FindUpdated(IList<MyClass> records, List<int> updatedIds)
{
IDictionary<int, int> foundItems = new Dictionary<int, int>();
if (records != null && updatedIds != null)
{
for (int i = 0; i < records.Count; i++)
{
IMyClass r = records[i] as IMyClass ;
if (r != null && !r.IsDisposed)
{
if (updatedIds.Contains(r.Id))
{
foundItems.Add(r.Id, i);
}
}
}
}
return foundItems;
}
В результате вызова FindUpdates()
я получаю Dictionary<Id, Data>
существующих записей, Dictionary<Id, Data>
обновленных записей для их замены и List<int>
идентификаторов, для которых элементы должны быть добавлены, удалены или обновлены из источника данных.
Иногда запись добавляется в сетку дважды, и я не могу понять, где этот код работает неправильно.
Я вытащил файл журнала из одного из этих экземпляров и ясно вижу следующую последовательность событий:
- Пункт №2 добавлен в Список данных
- Через 20 минут элемент № 2 снова добавляется в список данных.
WriteToLog()
из 2-го добавления говорит мне, что
updatedIds
содержит значения 1, 2 и 3adds
содержит 1 и 2updates
содержит 3
Основываясь на других записях журнала, я ясно вижу, что элемент № 2 был добавлен ранее и никогда не удалялся, поэтому он должен быть в переменной existingRecords
, отображаемой в переменной updates
, а не в adds
. Кроме того, элемент № 2 был успешно обновлен несколько раз между первым и вторым добавлением, поэтому теоретически код должен работать. У меня также есть скриншот пользовательского интерфейса, показывающий обе копии элемента № 2 в сетке данных.
Примечания...
IsDisposed
имеет значение true только в переопределенном методе.Dispose()
элемента. Я не думаю, что это произошло бы.Изменить. С тех пор я добавил отчет в журнал и могу убедиться, что
IsDisposed
не установлено наtrue
, когда это происходит.Это случалось несколько раз с несколькими разными пользователями, так что это не разовая вещь. Однако я не могу воспроизвести проблему по требованию.
Сетка записей может быть довольно большой, в среднем насчитывая несколько тысяч элементов.
Я не исключаю, что вызов БД возвращает недопустимые значения или списки, в которых нет одинаковых элементов, однако я не понимаю, как это может повлиять на результат.
Один раз, когда я смог увидеть эту ошибку в действии, мы запускали несколько тестов, и другие пользователи довольно часто изменяли запись № 2.
Все это работает в фоновом потоке
Судя по журналу, это было запущено только один раз. Раньше он запускался за минуту до, а затем через 2 минуты.
Из файла журнала я вижу, что элемент № 2 был обновлен несколько раз правильно, прежде чем был неправильно добавлен во второй раз, поэтому этот код работал с существующим набором данных несколько раз ранее.
Есть ли что-нибудь в коде, показанном выше, что может привести к этому? Или, возможно, это редкая известная проблема в C#, о которой я не знаю?
FindUpdated
эта строка:else if (updated.ContainsKey(id))
не должна быть такой? (с оператором отрицания (!)else if (!updated.ContainsKey(id))
- person Selman Genç   schedule 05.03.2014List<MyClass>
содержит комбинацию добавлений и обновлений, аList<int>
содержит идентификаторы для всех объявлений, обновлений и удалений. - person Rachel   schedule 05.03.2014FindUpdated
не возвращает, например,Set<int>
, или почему вы не используетеforeach
- но это совсем не выглядит алгоритмически неправильным. Меня беспокоит то, что вы сказали, что это работает в фоновом потоке. Есть ли в каком-либо другом потоке код, который может изменять объекты в выходных параметрах? Поскольку вы упомянули потоки, такие вещи просто воняют ошибкой параллельного обновления. Хотя я признаю, что путь, по которому это могло произойти, выглядит крайне неправдоподобно, поскольку вы в основном работаете с локальными данными. - person Matthew Walton   schedule 13.05.2014existingRecords
. Поскольку я привязываюсь к коллекции, я не думаю, что элемент управления пользовательского интерфейса повлияет на это, но сталкивались ли вы с чем-то подобным в прошлом? - person Rachel   schedule 13.05.2014