Пакетное обновление (VB)
Узнайте, как обновить несколько записей базы данных в одной операции. На уровне пользовательского интерфейса мы создадим GridView, где каждая строка редактируется. На уровне доступа к данным мы упаковаем несколько операций обновления в транзакции, чтобы убедиться, что все обновления успешно или все обновления откатываются.
Введение
В предыдущем руководстве мы узнали, как расширить уровень доступа к данным для добавления поддержки транзакций баз данных. Транзакции базы данных гарантируют, что ряд инструкций изменения данных будет рассматриваться как одна атомарная операция, которая гарантирует, что все изменения завершаются ошибкой или все будут выполнены успешно. Благодаря этой низкоуровневой функции DAL мы готовы обратить внимание на создание интерфейсов изменения пакетных данных.
В этом руководстве мы создадим GridView, где каждая строка редактируется (см. рис. 1). Так как каждая строка отрисовывается в интерфейсе редактирования, нет необходимости в столбце кнопок "Изменить", "Обновить" и "Отмена". Вместо этого на странице есть две кнопки "Обновить продукты", которые при щелчке перечисляют строки GridView и обновляют базу данных.
Рис. 1. Каждая строка в GridView редактируется (щелкните, чтобы просмотреть изображение полного размера)
Давайте приступим!
Примечание.
В руководстве по выполнению пакетных обновлений мы создали интерфейс пакетного редактирования с помощью элемента управления DataList. Это руководство отличается от предыдущего в том, что использует GridView, и пакетное обновление выполняется в области транзакции. После выполнения этого руководства мы рекомендуем вернуться к предыдущему руководству и обновить его, чтобы использовать функциональные возможности, связанные с транзакцией базы данных, добавленные в предыдущем руководстве.
Изучение шагов по изменению всех строк GridView
Как описано в руководстве по вставке, обновлению и удалению данных , GridView предлагает встроенную поддержку редактирования базовых данных на основе строк. Внутри сетки GridView отмечает, какая строка редактируется через его EditIndex
свойство. Так как GridView привязан к источнику данных, он проверяет каждую строку, чтобы узнать, равен ли индекс строки значению EditIndex
. Если это так, поля строки отображаются с помощью интерфейсов редактирования. Для BoundFields интерфейс редактирования является TextBox, свойство которого Text
присваивается значению поля данных, заданного свойством BoundField DataField
. Для TemplateFields EditItemTemplate
используется вместо ItemTemplate
.
Помните, что рабочий процесс редактирования начинается, когда пользователь нажимает кнопку "Изменить строку". Это приводит к обратной обратной отправке, задает свойство GridView EditIndex
индексу нажатой строки и повторно привязывает данные к сетке. При нажатии кнопки "Отмена строки" для обратной передачи EditIndex
задано значение -1
перед повторной привязкой данных к сетке. Так как строки GridView начинают индексироваться с нуля, параметр EditIndex
имеет -1
эффект отображения GridView в режиме только для чтения.
Свойство EditIndex
хорошо подходит для редактирования строк, но не предназначено для пакетного редактирования. Чтобы сделать весь gridView редактируемым, необходимо иметь каждую строку отрисовки с помощью интерфейса редактирования. Самый простой способ сделать это — создать, где каждое редактируемое поле реализуется как TemplateField с его интерфейсом редактирования, определенным в .ItemTemplate
На следующих нескольких шагах мы создадим полностью редактируемый GridView. На шаге 1 мы создадим GridView и ObjectDataSource и преобразуем его BoundFields и CheckBoxField в TemplateFields. В шагах 2 и 3 мы переместим интерфейсы редактирования из шаблонных полей EditItemTemplate
на их ItemTemplate
.
Шаг 1. Отображение сведений о продукте
Прежде чем беспокоиться о создании GridView, где являются строки редактируемыми, давайте начнем с простого отображения сведений о продукте. BatchUpdate.aspx
Откройте страницу в папке BatchData
и перетащите GridView из панели элементов в конструктор. Задайте для GridView значение ID
ProductsGrid
и из смарт-тега выберите для привязки его к новому объекту ObjectDataSource с именем ProductsDataSource
. Настройте ObjectDataSource для получения данных из ProductsBLL
метода класса GetProducts
.
Рис. 2. Настройка ObjectDataSource для использования ProductsBLL
класса (щелкните, чтобы просмотреть изображение полного размера)
Рис. 3. Получение данных продукта с помощью GetProducts
метода (щелкните, чтобы просмотреть изображение полного размера)
Как и в GridView, функции изменения ObjectDataSource предназначены для работы на основе каждой строки. Чтобы обновить набор записей, необходимо написать немного кода в классе кода ASP.NET страницы, который пакетирует данные и передает его в BLL. Таким образом, задайте раскрывающийся список на вкладках UPDATE, INSERT и DELETE объекта ObjectDataSource значение (Нет). Чтобы завершить работу мастера, нажмите кнопку Готово .
Рис. 4. Задайте раскрывающийся список в вкладках UPDATE, INSERT и DELETE (Нет) (Щелкните, чтобы просмотреть изображение полного размера)
После завершения мастера настройки источника данных декларативная разметка ObjectDataSource должна выглядеть следующим образом:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Завершение работы мастера настройки источника данных также приводит к созданию BoundFields и CheckBoxField для полей данных продукта в GridView. В этом руководстве давайте разрешим пользователю просматривать и изменять имя продукта, категорию, цену и прекращенное состояние. Удалите все ProductName
CategoryName
поля и UnitPrice
поля, а Discontinued
также переименуйте HeaderText
свойства первых трех полей в Product, Category и Price соответственно. Наконец, установите флажки "Включить разбиение по страницам" и "Включить сортировку" в смарт-теге GridView.
На этом этапе GridView имеет три BoundFields (ProductName
, CategoryName
и UnitPrice
) и CheckBoxField (Discontinued
). Необходимо преобразовать эти четыре поля в TemplateFields, а затем переместить интерфейс редактирования из TemplateField s EditItemTemplate
в его ItemTemplate
.
Примечание.
Мы изучили создание и настройку TemplateFields в руководстве по настройке интерфейса изменения данных. Мы рассмотрим шаги по преобразованию BoundFields и CheckBoxField в TemplateFields и определению их интерфейсов редактирования в своих ItemTemplate
s, но если вы застряли или нуждаетесь в обновлении, не стесняйтесь обращаться к этому предыдущему руководству.
В смарт-теге GridView щелкните ссылку "Изменить столбцы", чтобы открыть диалоговое окно "Поля". Затем выберите каждое поле и нажмите кнопку "Преобразовать это поле" в ссылку TemplateField.
Рис. 5. Преобразование существующих boundFields и CheckBoxField в TemplateFields
Теперь, когда каждое поле является templateField, мы готовы переместить интерфейс редактирования из EditItemTemplate
s в ItemTemplate
s.
Шаг 2. СозданиеProductName
интерфейсовUnitPrice
иDiscontinued
редактирование интерфейсов
ProductName
Создание интерфейсов редактирования UnitPrice
и Discontinued
редактирования являются темой этого шага и довольно просто, так как каждый интерфейс уже определен в templateField sEditItemTemplate
. CategoryName
Создание интерфейса редактирования немного больше связано с тем, что нам нужно создать DropDownList применимых категорий. Этот CategoryName
интерфейс редактирования решается на шаге 3.
Начнем с ProductName
TemplateField. Щелкните ссылку "Изменить шаблоны" из смарт-тега GridView и выполните детализацию до ProductName
шаблонаField EditItemTemplate
. Выберите текстовое поле, скопируйте его в буфер обмена, а затем вставьте его в ProductName
файл TemplateField s ItemTemplate
. Измените свойство TextBox ID
на ProductName
.
Затем добавьте RequiredFieldValidator ItemTemplate
в поле, чтобы убедиться, что пользователь предоставляет значение для каждого продукта. ControlToValidate
Задайте для свойства значение ProductName, ErrorMessage
для свойства необходимо указать имя продукта. Text
и свойство *. После добавления этих дополнений ItemTemplate
на экран должен выглядеть примерно так же, как на рис. 6.
Рис. 6. ШаблонФилд ProductName
теперь включает текстовое поле и ОбязательныйFieldValidator (щелкните, чтобы просмотреть изображение полного размера)
UnitPrice
Для интерфейса редактирования начните с копирования Текстового поля из ItemTemplate
. Затем поместите $ перед TextBox и задайте для свойства ID
UnitPrice и его Columns
свойства значение 8.
Кроме того, добавьте CompareValidator UnitPrice
в s ItemTemplate
, чтобы убедиться, что значение, введенное пользователем, является допустимым значением валюты больше или равно $0,00. Присвойте свойству проверяющего элемента ControlToValidate
значение UnitPrice, его ErrorMessage
свойству необходимо ввести допустимое значение валюты. Опустите любые символы валюты., его свойство *, Text
его Type
свойство to, его свойство Currency
to, и его Operator
ValueToCompare
свойство GreaterThanEqual
до 0.
Рис. 7. Добавление compareValidator, чтобы убедиться, что введенная цена является неотрицательной денежной стоимостью (щелкните, чтобы просмотреть изображение полного размера)
Discontinued
Для TemplateField можно использовать флажок, уже определенный в файле ItemTemplate
. Просто задайте значение ID
"Прекращено" и его Enabled
свойство True
.
Шаг 3. СозданиеCategoryName
интерфейса редактирования
Интерфейс редактирования в CategoryName
templateField содержит EditItemTemplate
текстовое поле, отображающее значение CategoryName
поля данных. Для этого нужно заменить раскрывающийся список возможных категорий.
Примечание.
Руководство по настройке интерфейса изменения данных содержит более тщательное и полное обсуждение настройки шаблона для включения dropDownList в отличие от текстового поля. Пока шаги здесь завершены, они представлены ужасно. Дополнительные сведения о создании и настройке категорий DropDownList см. в руководстве по настройке интерфейса изменения данных.
Перетащите раскрывающийся список из панели элементов в CategoryName
шаблонФилд ItemTemplate
, задав для нее значение ID
Categories
. На этом этапе мы обычно определим источник данных DropDownLists с помощью смарт-тега, создав объект ObjectDataSource. Однако это добавит ObjectDataSource в объект ItemTemplate
, который приведет к экземпляру ObjectDataSource, созданному для каждой строки GridView. Вместо этого давайте создадим ОбъектDataSource за пределами TemplateFields GridView. Завершите редактирование шаблона и перетащите ОбъектDataSource из панели элементов в конструктор под ProductsDataSource
ObjectDataSource. Назовите новый ObjectDataSource CategoriesDataSource
и настройте его для использования CategoriesBLL
метода класса GetCategories
.
Рис. 8. Настройка ObjectDataSource для использования CategoriesBLL
класса (щелкните, чтобы просмотреть изображение полного размера)
Рис. 9. Получение данных категории с помощью GetCategories
метода (щелкните, чтобы просмотреть изображение полного размера)
Так как этот ОбъектDataSource используется только для извлечения данных, задайте раскрывающийся список на вкладках UPDATE и DELETE (Нет). Чтобы завершить работу мастера, нажмите кнопку Готово .
Рис. 10. Установите раскрывающийся список на вкладках UPDATE и DELETE (Нет) (Щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера CategoriesDataSource
декларативная разметка должна выглядеть следующим образом:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
CategoriesDataSource
После создания и настройки вернитесь к CategoryName
шаблону TemplateField ItemTemplate
и в смарт-теге DropDownList щелкните ссылку "Выбор источника данных". В мастере настройки источника данных выберите CategoriesDataSource
параметр из первого раскрывающегося списка и выберите CategoryName
для отображения и CategoryID
в качестве значения.
Рис. 11. Привязка раскрывающегося списка к CategoriesDataSource
списку (щелкните, чтобы просмотреть изображение полного размера)
На этом этапе Categories
в раскрывающемся списке перечислены все категории, но она пока не выбирает соответствующую категорию для продукта, привязанного к строке GridView. Для этого необходимо задать значение Categories
DropDownList в SelectedValue
CategoryID
значении продукта. Щелкните ссылку "Изменить DataBindings" из смарт-тега DropDownList и свяжите SelectedValue
свойство с полем CategoryID
данных, как показано на рис. 12.
Рис. 12. Привязка значения продукта CategoryID
к свойству DropDownList SelectedValue
Одна из последних проблем остается: если продукт не имеет указанного CategoryID
значения, то оператор SelectedValue
привязки данных приведет к исключению. Это связано с тем, что DropDownList содержит только элементы для категорий и не предлагает вариант для тех продуктов, для которых задано NULL
значение CategoryID
базы данных. Чтобы устранить эту проблему, задайте свойство True
DropDownList и добавьте новый элемент в DropDownListAppendDataBoundItems
, опустив Value
свойство из декларативного синтаксиса. То есть убедитесь, что Categories
декларативный синтаксис DropDownList выглядит следующим образом:
<asp:DropDownList ID="Categories" runat="server" AppendDataBoundItems="True"
DataSourceID="CategoriesDataSource" DataTextField="CategoryName"
DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
<asp:ListItem Value=">-- Select One --</asp:ListItem>
</asp:DropDownList>
Обратите внимание, что атрибут <asp:ListItem Value="">
select One Value
явно задается пустой строкой. Вернитесь к руководству по настройке интерфейса изменения данных, чтобы более подробно обсудить, почему этот дополнительный элемент DropDownList необходим для обработки NULL
дела и почему назначение Value
свойства пустой строке является важным.
Примечание.
Здесь существует потенциальная проблема с производительностью и масштабируемостью, которую стоит упомянуть. Так как каждая строка имеет DropDownList, использующего CategoriesDataSource
его источник данных, метод класса GetCategories
будет вызываться n раз на посещение страницыCategoriesBLL
, где n — количество строк в GridView. Эти вызовы n приводят к выполнению GetCategories
n-запросов к базе данных. Это влияние на базу данных может уменьшиться путем кэширования возвращаемых категорий в кэше каждого запроса или на уровне кэширования с помощью зависимостей кэширования SQL или очень короткого срока действия на основе времени.
Шаг 4. Завершение интерфейса редактирования
Мы внесли ряд изменений в шаблоны GridView без приостановки просмотра хода выполнения. Ознакомьтесь с нашим прогрессом в браузере. Как показано на рисунке 13, каждая строка отрисовывается с помощью своего ItemTemplate
интерфейса редактирования ячейки.
Рис. 13. Каждая строка GridView редактируется (щелкните, чтобы просмотреть изображение полного размера)
На этом этапе мы должны заботиться о нескольких незначительных проблемах форматирования. Во-первых, обратите внимание, что UnitPrice
значение содержит четыре десятичных знака. Чтобы устранить эту проблему, вернитесь к UnitPrice
шаблону и ItemTemplate
из смарт-тега TextBox щелкните ссылку "Изменить DataBindings". Затем укажите, что Text
свойство должно быть отформатировано как число.
Рис. 14. Форматирование Text
свойства в виде числа
Во-вторых, разместим флажок в Discontinued
столбце (вместо выравнивания по левому краю). Щелкните "Изменить столбцы" в смарт-теге GridView и выберите Discontinued
TemplateField из списка полей в левом нижнем углу. ItemStyle
Детализация и установка HorizontalAlign
свойства в Центр, как показано на рис. 15.
Рис. 15. Центр Discontinued
флажка
Затем добавьте элемент управления ValidationSummary на страницу и задайте для его ShowMessageBox
свойства True
значение и его ShowSummary
свойство False
. Кроме того, добавьте веб-элементы управления button, которые при нажатии будут обновлять изменения пользователя. В частности, добавьте два веб-элемента управления Button, один над GridView и один под ним, задав оба свойства элементов управления Text
для update Products.
Так как интерфейс редактирования GridView определен в его TemplateFields ItemTemplate
, EditItemTemplate
они являются лишними и могут быть удалены.
После внесения указанных выше изменений форматирования, добавления элементов управления Button и удаления ненужных EditItemTemplate
элементов синтаксис страницы должен выглядеть следующим образом:
<p>
<asp:Button ID="UpdateAllProducts1" runat="server" Text="Update Products" />
</p>
<p>
<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
AllowPaging="True" AllowSorting="True">
<Columns>
<asp:TemplateField HeaderText="Product" SortExpression="ProductName">
<ItemTemplate>
<asp:TextBox ID="ProductName" runat="server"
Text='<%# Bind("ProductName") %>'></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ControlToValidate="ProductName"
ErrorMessage="You must provide the product's name."
runat="server">*</asp:RequiredFieldValidator>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Category"
SortExpression="CategoryName">
<ItemTemplate>
<asp:DropDownList ID="Categories" runat="server"
AppendDataBoundItems="True"
DataSourceID="CategoriesDataSource"
DataTextField="CategoryName"
DataValueField="CategoryID"
SelectedValue='<%# Bind("CategoryID") %>'>
<asp:ListItem>-- Select One --</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Price"
SortExpression="UnitPrice">
<ItemTemplate>
$<asp:TextBox ID="UnitPrice" runat="server" Columns="8"
Text='<%# Bind("UnitPrice", "{0:N}") %>'></asp:TextBox>
<asp:CompareValidator ID="CompareValidator1" runat="server"
ControlToValidate="UnitPrice"
ErrorMessage="You must enter a valid currency value.
Please omit any currency symbols."
Operator="GreaterThanEqual" Type="Currency"
ValueToCompare="0">*</asp:CompareValidator>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<asp:CheckBox ID="Discontinued" runat="server"
Checked='<%# Bind("Discontinued") %>' />
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
</Columns>
</asp:GridView>
</p>
<p>
<asp:Button ID="UpdateAllProducts2" runat="server" Text="Update Products" />
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
<asp:ValidationSummary ID="ValidationSummary1" runat="server"
ShowMessageBox="True" ShowSummary="False" />
</p>
На рисунке 16 показана эта страница при просмотре через браузер после добавления веб-элементов управления button и внесенных изменений форматирования.
Рис. 16. Страница теперь включает две кнопки обновления продуктов (щелкните, чтобы просмотреть изображение полного размера)
Шаг 5. Обновление продуктов
Когда пользователь посещает эту страницу, он будет вносить изменения и нажимать одну из двух кнопок "Обновить продукты". На этом этапе необходимо как-то сохранить введенные пользователем значения для каждой ProductsDataTable
строки в экземпляр, а затем передать его в метод BLL, который затем передает этот ProductsDataTable
экземпляр методу DAL UpdateWithTransaction
. Метод UpdateWithTransaction
, созданный в предыдущем руководстве, гарантирует, что пакет изменений будет обновлен как атомарная операция.
Создайте метод с именем BatchUpdate
и BatchUpdate.aspx.vb
добавьте следующий код:
Private Sub BatchUpdate()
' Enumerate the GridView's Rows collection and create a ProductRow
Dim productsAPI As New ProductsBLL()
Dim products As Northwind.ProductsDataTable = productsAPI.GetProducts()
For Each gvRow As GridViewRow In ProductsGrid.Rows
' Find the ProductsRow instance in products that maps to gvRow
Dim productID As Integer = _
Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
Dim product As Northwind.ProductsRow = products.FindByProductID(productID)
If product IsNot Nothing Then
' Programmatically access the form field elements in the
' current GridViewRow
Dim productName As TextBox = _
CType(gvRow.FindControl("ProductName"), TextBox)
Dim categories As DropDownList = _
CType(gvRow.FindControl("Categories"), DropDownList)
Dim unitPrice As TextBox = _
CType(gvRow.FindControl("UnitPrice"), TextBox)
Dim discontinued As CheckBox = _
CType(gvRow.FindControl("Discontinued"), CheckBox)
' Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim()
If categories.SelectedIndex = 0 Then
product.SetCategoryIDNull()
Else
product.CategoryID = Convert.ToInt32(categories.SelectedValue)
End If
If unitPrice.Text.Trim().Length = 0 Then
product.SetUnitPriceNull()
Else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
End If
product.Discontinued = discontinued.Checked
End If
Next
' Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products)
End Sub
Этот метод начинается с получения всех продуктов обратно в ProductsDataTable
методе BLL GetProducts
. Затем он перечисляет коллекцию ProductGrid
GridViewRows
. Коллекция Rows
содержит экземпляр для каждой GridViewRow
строки, отображаемой в GridView. Так как мы отображаем не более десяти строк на страницу, коллекция GridView Rows
будет иметь не более десяти элементов.
Для каждой строкиProductID
, полученной DataKeys
из коллекции, выбран ProductsDataTable
соответствующий ProductsRow
параметр. Четыре элемента управления входных данных TemplateField программно ссылаются и их значения, назначенные свойствам экземпляра ProductsRow
. После того как значения строк GridView были использованы для обновления ProductsDataTable
, он передается методу BLL UpdateWithTransaction
, который, как мы видели в предыдущем руководстве, просто вызывается в метод DAL UpdateWithTransaction
.
Алгоритм пакетного обновления, используемый для этого руководства, обновляет каждую строку в ProductsDataTable
строке в GridView независимо от того, были ли изменены сведения о продукте. Хотя такие слепые обновления обычно не являются проблемой производительности, они могут привести к лишним записям, если вы выполняете аудит изменений в таблице базы данных. В руководстве по выполнению пакетных обновлений мы изучили интерфейс пакетного обновления с помощью DataList и добавили код, который будет обновлять только те записи, которые фактически были изменены пользователем. При необходимости вы можете использовать методы выполнения пакетных обновлений для обновления кода в этом руководстве.
Примечание.
При привязке источника данных к GridView с помощью смарт-тега Visual Studio автоматически назначает значения первичного ключа источника данных свойству GridView DataKeyNames
. Если объект ObjectDataSource не привязывается к GridView с помощью смарт-тега GridView, как описано на шаге 1, необходимо вручную задать для свойства GridView DataKeyNames
значение ProductID, чтобы получить доступ к ProductID
значению каждой строки через DataKeys
коллекцию.
Код, используемый в BatchUpdate
методах BLL, аналогичен тому, что в UpdateProduct
методах BLL UpdateProduct
извлекается только один ProductRow
экземпляр. Код, назначающий свойства этого ProductRow
объекта, совпадает с UpdateProducts
методами и кодом в цикле For Each
BatchUpdate
, как и общий шаблон.
Чтобы завершить работу с этим руководством, необходимо вызвать BatchUpdate
метод при нажатии любой из кнопок Update Products. Создайте обработчики событий для Click
этих двух элементов управления Button и добавьте следующий код в обработчики событий:
BatchUpdate()
ClientScript.RegisterStartupScript(Me.GetType(), "message", _
"alert('The products have been updated.');", True)
Сначала вызов выполняется BatchUpdate
. ClientScript
Затем свойство используется для внедрения JavaScript, в котором будет отображаться сообщение, которое считывает продукты, были обновлены.
Минуту, чтобы проверить этот код. Посетите BatchUpdate.aspx
браузер, измените ряд строк и нажмите одну из кнопок "Обновить продукты". Если ошибки проверки входных данных отсутствуют, вы увидите сообщение, которое считывает обновленные продукты. Чтобы проверить атомарность обновления, попробуйте добавить случайное CHECK
ограничение, например UnitPrice
значение 1234,56. BatchUpdate.aspx
Затем отредактируйте ряд записей, убедившись, что одно из значений продукта UnitPrice
имеет запрещенное значение (1234,56). Это приведет к ошибке при нажатии кнопки "Обновить продукты" с другими изменениями во время пакетной операции отката к исходным значениям.
АльтернативныйBatchUpdate
метод
Метод BatchUpdate
, который мы только что изучили, извлекает все продукты из метода BLL GetProducts
, а затем обновляет только те записи, которые отображаются в GridView. Этот подход идеально подходит, если GridView не использует разбиение по страницам, но если это делает, может быть сотни, тысячи или десятки тысяч продуктов, но только десять строк в GridView. В таком случае получение всех продуктов из базы данных только для изменения 10 из них меньше идеала.
Для таких типов ситуаций рекомендуется использовать следующий BatchUpdateAlternate
метод:
Private Sub BatchUpdateAlternate()
' Enumerate the GridView's Rows collection and create a ProductRow
Dim productsAPI As New ProductsBLL()
Dim products As New Northwind.ProductsDataTable()
For Each gvRow As GridViewRow In ProductsGrid.Rows
' Create a new ProductRow instance
Dim productID As Integer = _
Convert.ToInt32(ProductsGrid.DataKeys(gvRow.RowIndex).Value)
Dim currentProductDataTable As Northwind.ProductsDataTable = _
productsAPI.GetProductByProductID(productID)
If currentProductDataTable.Rows.Count > 0 Then
Dim product As Northwind.ProductsRow = currentProductDataTable(0)
Dim productName As TextBox = _
CType(gvRow.FindControl("ProductName"), TextBox)
Dim categories As DropDownList = _
CType(gvRow.FindControl("Categories"), DropDownList)
Dim unitPrice As TextBox = _
CType(gvRow.FindControl("UnitPrice"), TextBox)
Dim discontinued As CheckBox = _
CType(gvRow.FindControl("Discontinued"), CheckBox)
' Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim()
If categories.SelectedIndex = 0 Then
product.SetCategoryIDNull()
Else
product.CategoryID = Convert.ToInt32(categories.SelectedValue)
End If
If unitPrice.Text.Trim().Length = 0 Then
product.SetUnitPriceNull()
Else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text)
End If
product.Discontinued = discontinued.Checked
' Import the ProductRow into the products DataTable
products.ImportRow(product)
End If
Next
' Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products)
End Sub
BatchMethodAlternate
запускается путем создания пустого ProductsDataTable
имени products
. Затем он выполняет шаги по коллекции GridView Rows
и для каждой строки получает определенную информацию о продукте с помощью метода BLL GetProductByProductID(productID)
. Полученный ProductsRow
экземпляр имеет свои свойства, обновленные таким же образом, как BatchUpdate
и после обновления строки, импортируемой в products
ProductsDataTable
метод DataTableImportRow(DataRow)
.
После завершения products
цикла содержит один ProductsRow
экземпляр для каждой For Each
строки в GridView. Так как каждый ProductsRow
из экземпляров был добавлен products
в (вместо обновления), если мы слепо передаем его UpdateWithTransaction
методу, ProductsTableAdapter
то попытается вставить каждую из записей в базу данных. Вместо этого необходимо указать, что каждая из этих строк была изменена (не добавлена).
Это можно сделать, добавив новый метод в BLL с именем UpdateProductsWithTransaction
. UpdateProductsWithTransaction
, как показано ниже, задает каждый из ProductsRow
экземпляров в списке ProductsDataTable
Modified
, а затем передает ProductsDataTable
метод DALUpdateWithTransaction
.RowState
Public Function UpdateProductsWithTransaction _
(ByVal products As Northwind.ProductsDataTable) As Integer
' Mark each product as Modified
products.AcceptChanges()
For Each product As Northwind.ProductsRow In products
product.SetModified()
Next
' Update the data via a transaction
Return UpdateWithTransaction(products)
End Function
Итоги
GridView предоставляет встроенные возможности редактирования строк, но не поддерживает создание полностью редактируемых интерфейсов. Как мы видели в этом руководстве, такие интерфейсы возможны, но требуют немного работы. Чтобы создать GridView, где каждая строка редактируется, необходимо преобразовать поля GridView в TemplateFields и определить интерфейс редактирования в пределах ItemTemplate
S. Кроме того, необходимо добавить на страницу веб-элементы управления "Все кнопки типа" отдельно от GridView. Эти обработчики событий Button Click
должны перечислить коллекцию GridView Rows
, сохранить изменения в объекте ProductsDataTable
и передать обновленные сведения в соответствующий метод BLL.
В следующем руководстве мы посмотрим, как создать интерфейс для удаления пакетной службы. В частности, каждая строка GridView будет включать флажок и вместо кнопок "Обновить все тип", у нас будут кнопки "Удалить выбранные строки".
Счастливое программирование!
Об авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 2.0 в 24 часах. Он может быть достигнут в mitchell@4GuysFromRolla.com. или через его блог, который можно найти на http://ScottOnWriting.NET.
Особое спасибо
Эта серия учебников была проверена многими полезными рецензентами. Ведущие рецензенты для этого руководства были Тереса Мерфи и Дэвид Суру. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.