Чтобы предотвратить эту проблему, разработчики часто используют параллелизм типа "сравнить все" или основанную на временных метках. Идея в том, что оператор UPDATE должен найти соответствие всех значений полей оригинальной записи, или же обновление не будет разрешено. Вот пример:
UPDATE Shippers SET CompanyName=@CompanyName, Phone=@Phone
WHERE ShipperID=@original_ShipperID AND CompanyName=@original_CompanyName
AND Phone=@original_Phone"
SQL Server использует индекс по полю первичного ключа ShipperID для нахождения записи, и затем сравнивает прочие поля, чтобы убедиться, что они совпадают. Обновление может быть выполнено успешно только в том случае, если значения полей записи совпадают с теми, которые пользователь видел, когда вносил свои изменения.
На заметку! Как отмечалось в главе 8, временные метки — более удачный способ решения этой проблемы, чем явное сравнение всех полей. Однако этот пример использует именно такой подход потому, что работает с существующей базой данных Northwind. В противном случае вам нужно будет добавить новый столбец временной метки.
Проблема стратегии параллелизма "сравнить все" состоит в том, что она может привести к сбоям редактирования. А именно: если запись была изменена кем-то другим между моментом, когда пользователь запросил ее и моментом, когда он выполняет обновление, то такое обновление не удастся. Фактически привязанные к данным элементы управления даже не могут предупредить вас о проблеме: они просто выполняют команду UPDATE безо всякого эффекта, поскольку это не рассматривается (в SQL), как ошибочное условие.
Если вы решите применить параллелизм типа "сравнить все", то по крайней мере, вам нужно проверять утерянные обновления. Это можно сделать, обрабатывая событие ItemUpdated соответствующего элемента управления. Там вы можете проверить свойство AffectedRows объекта EventArgs. Если это свойство равно 0, значит ни одна запись не была обновлена, что почти всегда объясняется тем, что в результате редактирования кем-то другим запись изменилась, и конструкция WHERE оператора UPDATE не может найти соответствия. (Другие ошибки вроде неудавшейся попытки обновления из-за нарушения ключевого ограничения либо попытки подтвердить некорректные данные приводят к возбуждению ошибочной ситуации в источнике данных.)
Рассмотрим пример, проверяющий неудачу обновления в элементе управления DetailsView с выдачей пользователю информации о проблеме:
protected void DetailsView1_ItemUpdated(object sender,
DetailsViewUpdatedEventArgs e)
{
if (e.AffectedRows == 0)
{
lblStatus.Text =
"Конфликтующее изменение уже было проведено в данной " +
"записи другим пользователем. Запись не обновлена.";
}
}
предыдущая следующая страница вначало главы оглавление
476