Опубликован: 25.09.2008 | Доступ: свободный | Студентов: 3223 / 516 | Оценка: 4.32 / 3.98 | Длительность: 18:50:00
ISBN: 978-5-94774-991-5
Лекция 10:

Использование баз данных в приложениях ASP.NET

< Лекция 9 || Лекция 10: 12345678910

Обновление данных

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

Определим в SqlDataSource запрос на обновление данных ( UpdateQuery ). Текст запроса будет выглядеть следующим образом:

UPDATE Закупки SET ДатаОперации = @ДатаОперации, Количество =
 @Количество, Цена = @Цена, КодКонтрагента = @Контрагент WHERE
 (КодОперации = @КодОперации)

При составлении запроса важно давать имена параметрам таким образом, чтобы они совпадали с именами столбцов таблицы. Это объясняется тем, что ASP.NET автоматически отправляет значения параметрам, взятым из столбцов, у которых имена совпадают с именами параметров.

В данном же примере присутствует еще одна особенность, которую следует учитывать. Она состоит в том, что ранее для удобства отображения данных был использован запрос, в котором происходит внутреннее соединение данных из таблиц "Контрагенты" и "Закупки", - он необходим для подмены номеров контрагентов их наименованиями. Поэтому при отображении информации в GridView мы видим наименования контрагентов вместо их номеров. Однако, это создаст некоторые трудности при реализации обновления данных. Дело в том, что теперь мы не можем реализовать обновление данных контрагентов, так как они находятся в таблице "Контрагенты", а SqlDataSource связан с таблицей "Закупки". Все, что мы можем сделать, - это изменить номер текущего контрагента в редактируемой операции закупки. При этом необходимо будет вводить не наименование контрагента, а его номер. Именно этим объясняется наличие в запросе параметра КодКонтрагента = @Контрагент, обновляющего и нформацию о контрагенте текущей операции закупки.

Добавим в GridView новый столбец. Для этого в интеллектуальном дескрипторе выполним команду Add New Column... ( рис. 10.26).

Добавление столбца в GridView с помощью интеллектульного дескриптора

увеличить изображение
Рис. 10.26. Добавление столбца в GridView с помощью интеллектульного дескриптора

В открывшемся окне ( рис. 10.27) установим тип поля CommandField, а также убедимся, что установлен флажок Edit/Update. Если требуется добавить также и возможность удаления элемента, необходимо установить флажок Delete.

Окно добавления нового столбца к GridView

Рис. 10.27. Окно добавления нового столбца к GridView

После этого в GridView будет добавлен столбец, в каждой строке которого рядом со значениями элементов строк будет добавлена ссылка Edit. После щелчка по этой ссылке соответствующая строка GridView будет переведена в режим редактирования, в результате чего все ячейки, за исключением столбцов, доступных только для чтения и не определенных в команде Update, превратятся в текстовые поля, а ссылка Edit будет заменена ссылками Update и Cancel, предназначенными для подтверждения внесения изменений в БД либо для их отмены ( рис. 10.28).

Редактирование содержимого таблицы "Закупки" с помощью GridView

Рис. 10.28. Редактирование содержимого таблицы "Закупки" с помощью GridView

При обновлении данных в базе могут возникать серьезные затруднения, вызванные возможностью одновременной работы большого количества пользователей с одними и теми же данными. Это особенно актуально для Web-приложений, количество пользователей которых может быть в несколько раз больше, чем для традиционных win32-приложений. Достаточно подробное описание возможных проблем и путей их решения можно найти в [ 7 ] . Остановимся лишь на некоторых из них, наиболее актуальных и востребованных.

Особые случаи обновления данных

Если посмотреть на текст запроса на обновление данных таблицы "Закупки", использованный в предыдущем примере, можно заметить, что очень важным его элементом является строка WHERE (КодОперации = @КодОперации). Она позволяет обновить только ту строку, которая соответствует значению, определенному в параметре "КодОперации". Этот код хорошо работает, если в один и тот же момент времени одну запись пытается обновить только один человек. Если же представить, что в момент редактирования нами этой записи другой пользователь сможет изменить значение поля "КодОперации", то попытка обновления таблицы "Закупки", предпринимаемая нами, завершится неудачей, т. к. в таблице больше не существует строки с тем значением кода операции, которое было взято в качестве параметра в момент начала редактирования. Поэтому, чтобы быть уверенным в том, что попытка обновления завершится успешно, необходимо использовать лишь те значения первичных ключей, которые доступны только для чтения. Кроме того, параметр, который используется для хранения исходного значения ключевого поля, необходимого для обновления записи, рекомендуется помечать префиксом. Задать префикс можно с помощью свойства OldValuesParameterFormatString объекта SqlDataSource. Обычно в качестве префикса используется значение original_. Так, в приведенном выше примере строка WHERE с учетом префикса может быть записана следующим образом:

WHERE КодОперации=@original_КодОперации

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

UPDATE Закупки SET ДатаОперации = @ДатаОперации, Количество =
 @Количество, Цена = @Цена, КодКонтрагента = @Контрагент WHERE
 (КодОперации = @original_КодОперации AND ДатаОперации=
 @original_ДатаОперации AND Количество=@originalКоличество
 AND Цена=@original_Цена AND КодКонтрагента=@original_Контрагент)

Проблема в данном случае состоит в том, что использование префикса возможно только для ключевых полей таблицы, определенных в свойстве DataKeyNames объекта GridView. Понятно, что невозможно определить все поля таблицы в качестве ключевых. Поэтому лучшим решением будет использование свойства ConflictDetection объекта SqlDataSource равным значению CompareAllValues.

Рассмотренные способы привязки элементов отображения к источникам данных, а также возможности объекта SqlDataSource целесообразно применять только в относительно небольших приложениях. При необходимости создания сложного Web-приложения использование SqlDataSource может привести к возникновению многих проблем, вызванных недостатками данного элемента. К недостаткам SqlDataSource можно отнести следующие:

  • все запросы, предназначенные для манипулирования данными и их извлечения, встроены в страницу. Это приводит к тому, что при необходимости изменения логики доступа к данным нужно вносить изменения в страницу, что приводит к необходимости ее повторного тестирования и отладке.
  • каждая страница и даже каждый элемент, связанный с данными, нуждается в отдельном элементе SqlDataSource. Это, с одной стороны, крайне неэффективно при использовании одинаковых запросов на разных страницах, т. к. в этом случае необходимо дублировать одинаковые элементы на разных страницах. С другой стороны, поддерживать такой код крайне неудобно, т.к. может возникнуть ситуация, в которой изменения придется вносить в несколько элементов SqlDataSource. Для решения этих и многих других проблем, возникающих при использовании SqlDataSource, необходимо при разработке приложения использовать принципы построения трехуровневой архитектуры доступа к данным. Эти принципы рассматриваются ниже.
< Лекция 9 || Лекция 10: 12345678910