Как мы упоминали ранее, элементы управления с привязкой к данным хранят значения, передаваемые в источник данных, в независимых словарях Keys, Values (новые значения) и OldValues. По умолчанию SqlDataSource и ObjectDataSource игнорируют поле OldValues и используют только Ключи и Значения. Такое поведение обнаруживается свойством ConflictDetection источника данных, которому по умолчанию присвоено значение OverwriteChanges. Шаблон OverwriteChanges означает «сопоставлять только значение первичного ключа для обновления или удаления записи». Эта операция означает, что при обновлении или удалении записи не учитывается, изменилось ли базовое значение записи. В обычных обстоятельствах идеальным состоянием является разрешение операции обновления или удаления завершиться успешно только в том случае, если значение строки данных точно соответствует первоначально выбранному значению. В этой идеальной ситуации, если другой пользователь обновит строку между моментом ее выбора и моментом обновления, ваша операция обновления завершится неудачно. Источник данных также поддерживает эту операцию, устанавливая для свойства ConflictDetection значение CompareAllValues. В этом режиме источник данных будет применять OldValues к команде или методу и использовать эти значения, чтобы гарантировать, что операция обновления или удаления должна соответствовать всем значениям записи перед обновлением или удалением. записывать. Также необходимо установить для свойства OldValuesParameterFormatString допустимую строку формата компонента .NET Framework (например, «original_{0}»), чтобы указать, как следует переименовывать параметры в словарях OldValues и Keys, чтобы отличать их от параметров NewValues.
В следующем примере кода показаны типичные команды SQL, используемые элементом управления SqlDataSource в режимах OverwriteChanges и CompareAllValues. Поле ID считается полем первичного ключа. Обратите внимание, что последняя команда сравнивает все необработанные значения строк данных в предложении WHERE, а не только первичные ключи. В этом случае для OldValuesParameterFormatString источника данных необходимо установить значение «original_{0}».
ВЫБЕРИТЕ [ID], [Имя], [Адрес] из [Контакты]
-- Перезаписать изменения
ОБНОВЛЕНИЕ [Контакты] SET [Имя] = @Имя, [Адрес] = @Адрес ГДЕ [ID] = @ID
УДАЛИТЬ ИЗ [Контакты] ГДЕ [ID] = @ID
-- CompareAllValues
UPDATE [Контакты] SET [Имя] = @Имя, [Адрес] = @Адрес ГДЕ [ID] = @original_ID
И [Имя] = @исходное_имя И [Адрес] = @исходный_адрес
УДАЛИТЬ ИЗ [Контакты] ГДЕ [ID] = @original_ID И [Имя] = @original_Name
AND [Address] = @original_Address
Обратите внимание, что OldValues не требуется для операций вставки, а ConflictDetection имеет смысл только для операций обновления и удаления.
В следующем примере показано поведение при возникновении конфликта. Чтобы запустить этот пример, вы должны открыть два экземпляра примера в двух отдельных окнах браузера (дважды нажать «Запустить образец»). Затем нажмите кнопку «Редактировать» в одной и той же строке обеих форм, чтобы перевести строку в режим редактирования. Измените значение в первом окне и нажмите «Обновить». Обратите внимание, что обновление прошло успешно. Во втором окне введите новое значение в строку и нажмите «Обновить». Эта операция обновления не удалась, поскольку значение базовой строки данных уже было изменено первой операцией обновления. В этом примере проверяется свойство AffectedRows параметра события Updated или Deleted, которое равно 0, чтобы подтвердить возникновение конфликта.
<скрипт runat="сервер">
Защищенный Sub SqlDataSource1_Updated (отправитель как объект, e как SqlDataSourceStatusEventArgs)
Если e.AffectedRows = 0 Тогда
Response.Write("Строка изменена, обновление прервано<br />")
Конец, если
End Sub
Protected Sub SqlDataSource1_Deleted (отправитель как объект, e как SqlDataSourceStatusEventArgs)
Если e.AffectedRows = 0 Тогда
Response.Write("Строка изменена, удаление прервано<br />")
Конец, если
Конец субтитра
</script>
Когда при обновлении или удалении используется шаблонный пользовательский интерфейс, старые значения полей двусторонней привязки данных с использованием синтаксиса привязки будут сохранены. Для удаления это означает, что вы должны использовать синтаксис Bind для значений, привязанных к данным в ItemTemplate. Целью является сохранение старого значения, необходимого для операции удаления. Следующий пример демонстрирует этот метод.
<Столбцы>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<Шаблон предмета>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("ContactID") %>'></asp:Label>
</ItemTemplate>
<Шаблон EditItem>
<asp:Label ID="Label3" runat="server" Text='<%# Eval("ContactID") %>'></asp:Label>
</EditItemTemplate>
</asp:TemplateField>
<Шаблон предмета>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("ContactName") %>'></asp:Label>
</ItemTemplate>
<Шаблон EditItem>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("ContactName") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Столбцы>
</asp:GridView>
Вы можете аккуратно обрабатывать ошибки обнаружения конфликтов, сообщая пользователю, что базовые данные были изменены, отображая измененное значение пользователю и позволяя пользователю выбрать, отправить или отказаться от своей операции. В следующем примере демонстрируется один из возможных способов обнаружения конфликтов. Обратите внимание, что параметру события RowUpdated DetailsView передается словарь, который можно использовать для обнаружения введенных пользователем значений. Вы также можете установить свойство KeepInEditMode этого параметра события, чтобы сохранять DetailsView в режиме редактирования, пока пользователь решает, как справиться с конфликтом. В этом примере тестируется подход, аналогичный предыдущему: одновременное открытие двух окон для создания конфликтующих обновлений.
Защищенный дополнительный DetailsView1_ItemUpdated (отправитель ByVal как объект, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs)
Если e.AffectedRows = 0 Тогда
' Переводим DetailsView в режим редактирования и синхронизируем с базой данных e.KeepInEditMode = True
ДеталиПросмотр1.DataBind()
' Повторно заполняем DetailsView значениями, введенными пользователем.
Dim t как текстовое поле
t = DetailsView1.Rows(1).Cells(1).Controls(0)
t.Text = e.NewValues("ДатаЗаказа")
t = DetailsView1.Rows(2).Cells(1).Controls(0)
t.Text = e.NewValues("Страна доставки")
ErrorPanel.Visible = True
Еще
ErrorPanel.Visible = Ложь
Конец, если
End Sub
Protected Sub DetailsView1_ModeChanging (отправитель ByVal как объект, ByVal e As System.Web.UI.WebControls.DetailsViewModeEventArgs)
Если e.CancelingEdit = True AndAlso ErrorPanel.Visible = True Тогда
ErrorPanel.Visible = Ложь
Конец, если
Ситуация аналогична, когда
End Sub
использует ObjectDataSource.Обратите внимание: поскольку для свойства ConflictDetection источника данных установлено значение CompareAllValues, источник данных будет искать перегрузку UpdateContact, которая принимает необработанное значение каждого поля объекта Contact.
Вы также можете использовать свойство DataObjectTypeName и CompareAllValues вместе. В этом случае ObjectDataSource ищет перегрузку UpdateContact, которая принимает только два параметра (оба Contact). Первый параметр — это объект Contact, в котором хранится новое значение, а второй параметр — это объект Contact, в котором хранится старое значение.