Пакетное обновление (C#)
Узнайте, как обновить несколько записей базы данных за одну операцию. На уровне пользовательского интерфейса мы создадим GridView, в котором каждая строка доступна для редактирования. На уровне доступа к данным мы заключаем в оболочку несколько операций обновления в рамках транзакции, чтобы гарантировать успешное выполнение всех обновлений или откат всех обновлений.
Введение
В предыдущем руководстве мы узнали, как расширить уровень доступа к данным, чтобы добавить поддержку транзакций базы данных. Транзакции базы данных гарантируют, что ряд инструкций изменения данных будет рассматриваться как одна атомарная операция, которая гарантирует, что все изменения завершатся ошибкой или все будут успешными. С этой низкоуровневой функциональностью DAL мы готовы обратить наше внимание на создание интерфейсов пакетного изменения данных.
В этом руководстве мы создадим GridView, в котором каждая строка доступна для редактирования (см. рис. 1). Так как каждая строка отображается в интерфейсе редактирования, нет необходимости в столбце с кнопками "Изменить", "Обновить" и "Отмена". Вместо этого на странице есть две кнопки Update Products, которые при щелчке перечисляют строки GridView и обновляют базу данных.
Рис. 1. Каждая строка в GridView является редактируемой (щелкните, чтобы просмотреть полноразмерное изображение)
Приступим!
Примечание
В учебнике Выполнение пакетной Обновления мы создали интерфейс пакетного редактирования с помощью элемента управления DataList. Этот учебник отличается от предыдущего тем, что использует GridView, а пакетное обновление выполняется в область транзакции. После завершения работы с этим руководством я призываю вас вернуться к предыдущему руководству и обновить его, чтобы использовать функциональные возможности, связанные с транзакциями базы данных, добавленные в предыдущем руководстве.
Изучение шагов по обеспечению редактируемых строк GridView
Как описано в руководстве Общие сведения о вставке, обновлении и удалении данных , GridView предлагает встроенную поддержку редактирования базовых данных для каждой строки. На внутреннем сервере GridView замечает, какую строку можно изменить с помощью свойстваEditIndex
. Так как GridView привязывается к источнику данных, он проверяет каждую строку, чтобы узнать, равен ли индекс строки значению EditIndex
. В этом случае поля строки отрисовываются с помощью интерфейсов редактирования. Для BoundFields интерфейсом редактирования является TextBox, свойству которого Text
присваивается значение поля данных, заданное свойством BoundField s DataField
. Для TemplateFields EditItemTemplate
вместо используется ItemTemplate
.
Помните, что рабочий процесс редактирования начинается, когда пользователь нажимает кнопку "Изменить" строки. Это вызывает обратную передачу, задает для свойства GridView EditIndex
индекс щелкнутой строки и повторно привязает данные к сетке. При нажатии кнопки Отмена строки перед повторной -1
привязкой данных к сетке при обратной EditIndex
отправке задается значение . Так как строки GridView начинают индексироваться с нулевым значением, при установке значения EditIndex
-1
будет отображаться GridView в режиме только для чтения.
Свойство EditIndex
хорошо подходит для редактирования строк, но не предназначено для пакетного редактирования. Чтобы сделать весь элемент GridView редактируемым, необходимо, чтобы каждая строка отображала их с помощью интерфейса редактирования. Самый простой способ сделать это — создать, где каждое редактируемое поле реализуется как TemplateField с интерфейсом редактирования, определенным в ItemTemplate
.
В течение следующих нескольких шагов мы создадим полностью редактируемый GridView. На шаге 1 мы начнем с создания GridView и его ObjectDataSource и преобразования его BoundFields и CheckBoxField в TemplateFields. В шагах 2 и 3 мы переместим интерфейсы редактирования из templateFields EditItemTemplate
в их ItemTemplate
.
Шаг 1. Отображение сведений о продукте
Прежде чем мы создадим GridView, в котором доступны для редактирования строки, давайте просто отобразим сведения о продукте. Откройте страницу BatchUpdate.aspx
в папке BatchData
и перетащите элемент GridView с панели элементов на Designer. Задайте для gridView значение ID
ProductsGrid
и из смарт-тега привяжите его к новому объекту ObjectDataSource с именем ProductsDataSource
. Настройте ObjectDataSource для получения своих данных из ProductsBLL
метода класса s GetProducts
.
Рис. 2. Настройка ObjectDataSource для использования ProductsBLL
класса (щелкните для просмотра полноразмерного изображения)
Рис. 3. Получение данных о продукте GetProducts
с помощью метода (щелкните для просмотра полноразмерного изображения)
Как и GridView, функции изменения ObjectDataSource предназначены для работы в каждой строке. Чтобы обновить набор записей, необходимо написать фрагмент кода в классе программной части страницы ASP.NET, который пакетирует данные и передает их в BLL. Поэтому установите для раскрывающихся списков на вкладках ObjectDataSource UPDATE, INSERT и DELETE значение (Нет). Чтобы завершить работу мастера, нажмите кнопку Готово.
Рис. 4. Задайте для Drop-Down Списки на вкладках UPDATE, INSERT и DELETE значение (нет) (щелкните для просмотра полноразмерного изображения)
После завершения работы мастера настройки источника данных декларативная разметка ObjectDataSource должна выглядеть следующим образом:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
Завершение работы мастера настройки источника данных также приводит к тому, что Visual Studio создаст BoundFields и CheckBoxField для полей данных продукта в GridView. В этом руководстве пользователю разрешено только просматривать и изменять название продукта, категорию, цену и состояние прекращения. Удалите все ProductName
поля , CategoryName
, UnitPrice
и Discontinued
и переименуйте HeaderText
свойства первых трех полей в Product, Category и Price соответственно. Наконец, проверка флажки Включить разбиение по страницам и Включить сортировку в смарт-теге GridView.
На этом этапе GridView имеет три BoundField (ProductName
, CategoryName
и UnitPrice
) и CheckBoxField (Discontinued
). Необходимо преобразовать эти четыре поля в TemplateFields, а затем переместить интерфейс редактирования из TemplateField в EditItemTemplate
его ItemTemplate
.
Примечание
Мы изучили создание и настройку TemplateFields в учебнике Настройка интерфейса изменения данных . Мы рассмотрим шаги преобразования BoundFields и CheckBoxField в TemplateFields и определения их интерфейсов редактирования в их ItemTemplate
, но если вы зависли или вам нужно обновить, не стесняйтесь вернуться к этому предыдущему руководству.
В смарт-теге GridView щелкните ссылку Изменить столбцы, чтобы открыть диалоговое окно Поля. Затем выберите каждое поле и щелкните ссылку Преобразовать это поле в TemplateField.
Рис. 5. Преобразование существующих полей BoundField и CheckBoxField в templateField
Теперь, когда каждое поле является templateField, мы готовы переместить интерфейс редактирования из EditItemTemplate
s в .ItemTemplate
Шаг 2. СозданиеProductName
UnitPrice
иDiscontinued
редактирование интерфейсов
ProductName
Создание интерфейсов редактирования , UnitPrice
и Discontinued
является темой этого шага и довольно просто, так как каждый интерфейс уже определен в TemplateField.EditItemTemplate
Создание интерфейса редактирования CategoryName
немного сложнее, так как нам нужно создать Раскрывающийся список применимых категорий. Этот CategoryName
интерфейс редактирования решается на шаге 3.
Начнем с ProductName
TemplateField. Щелкните ссылку Изменить шаблоны в смарт-теге GridView и перейдите к шаблону ProductName
TemplateField .EditItemTemplate
Выберите элемент TextBox, скопируйте его в буфер обмена, а затем вставьте в ProductName
templateField s ItemTemplate
. Измените свойство ProductName
TextBox на ID
.
Затем добавьте RequiredFieldValidator в , ItemTemplate
чтобы убедиться, что пользователь предоставляет значение для каждого названия продукта. Задайте для ControlToValidate
свойства значение ProductName, а для ErrorMessage
свойства — значение Вы должны указать имя продукта. и свойство для Text
*. После внесения этих дополнений в ItemTemplate
экран должен выглядеть примерно так, как на рис. 6.
Рис. 6. TemplateField ProductName
Now includes a TextBox and a RequiredFieldValidator (Щелкните для просмотра полноразмерного изображения)
UnitPrice
Для интерфейса редактирования начните с копирования элемента TextBox из в EditItemTemplate
ItemTemplate
. Затем поместите $ перед элементом TextBox и задайте для его ID
свойства значение UnitPrice, а для свойства Columns
— значение 8.
Кроме того, добавьте CompareValidator в UnitPrice
объект , ItemTemplate
чтобы убедиться, что введенное пользователем значение является допустимым значением в валюте, превышающим или равным 0,00 долл. США. Задайте для свойства проверяющего ControlToValidate
элемента управления значение UnitPrice, а для его ErrorMessage
свойства — значение Необходимо ввести допустимое значение валюты. Опустите все символы валюты, свойство — Text
*, Type
свойство Currency
Operator
— , свойство — GreaterThanEqual
, а свойство — значение , а свойство ValueToCompare
— значение 0.
Рис. 7. Добавление CompareValidator, чтобы убедиться, что введенная цена является неотрицательной валютой (щелкните, чтобы просмотреть полноразмерное изображение)
Discontinued
Для TemplateField можно использовать элемент CheckBox, уже определенный ItemTemplate
в . Просто задайте для свойства ID
значение Не поддерживается, а для свойства Enabled
— значение true
.
Шаг 3. СозданиеCategoryName
интерфейса редактирования
Интерфейс редактирования в CategoryName
templateField EditItemTemplate
содержит элемент TextBox, отображающий значение CategoryName
поля данных. Нам нужно заменить его на DropDownList, в который перечислены возможные категории.
Примечание
Руководство по настройке интерфейса изменения данных содержит более подробное и полное обсуждение настройки шаблона для включения DropDownList, а не TextBox. Хотя шаги здесь завершены, они представлены немного. Дополнительные сведения о создании и настройке категорий DropDownList см. в руководстве По настройке интерфейса изменения данных .
Перетащите раскрывающийся список из панели элементов в CategoryName
templateField, ItemTemplate
задав для нее ID
значение Categories
. На этом этапе мы обычно определяем источник данных DropDownLists с помощью смарт-тега, создавая объект ObjectDataSource. Однако при этом объект ObjectDataSource будет добавлен в ItemTemplate
, что приведет к созданию экземпляра ObjectDataSource для каждой строки GridView. Вместо этого давайте создадим ObjectDataSource за пределами TemplateFields GridView. Завершите редактирование шаблона и перетащите объект ObjectDataSource из панели элементов в Designer под ProductsDataSource
ObjectDataSource. Присвойте новому объекту имя ObjectDataSource CategoriesDataSource
и настройте его для использования CategoriesBLL
метода класса s GetCategories
.
Рис. 8. Настройка ObjectDataSource для использования CategoriesBLL
класса (щелкните для просмотра полноразмерного изображения)
Рис. 9. Получение данных категории с помощью GetCategories
метода (щелкните для просмотра полноразмерного изображения)
Так как объект ObjectDataSource используется только для получения данных, задайте для раскрывающихся списков на вкладках UPDATE и DELETE значение (Нет). Чтобы завершить работу мастера, нажмите кнопку Готово.
Рис. 10. Задайте для Drop-Down Списки на вкладках 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
DropDownList выводит список всех категорий, но пока не выбирает соответствующую категорию для продукта, привязанного к строке GridView. Для этого необходимо задать Categories
в раскрывающемся списке SelectedValue
значение продукта CategoryID
. Щелкните ссылку Изменить DataBindings в смарт-теге DropDownList и свяжите SelectedValue
свойство с полем CategoryID
данных, как показано на рисунке 12.
Рис. 12. Привязка значения product к CategoryID
свойству DropDownList SelectedValue
Последняя проблема остается: если продукт не имеет указанного CategoryID
значения, инструкция привязки данных в SelectedValue
приведет к исключению. Это связано с тем, что DropDownList содержит только элементы для категорий и не предлагает вариант для тех продуктов, которые имеют NULL
значение базы данных для CategoryID
. Чтобы устранить эту проблему, задайте свойству DropDownList AppendDataBoundItems
значение true
и добавьте новый элемент в DropDownList, исключив 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
в качестве источника данных, CategoriesBLL
метод класса GetCategories
будет вызываться n раз за посещение страницы, где n — это количество строк в GridView. Эти вызовы n приводят к GetCategories
n запросам к базе данных. Это влияние на базу данных можно уменьшить путем кэширования возвращаемых категорий либо в кэше для каждого запроса, либо с помощью уровня кэширования с использованием зависимости кэширования SQL или очень короткого срока действия.
Шаг 4. Завершение работы с интерфейсом редактирования
Мы внесли ряд изменений в шаблоны GridView без приостановки для просмотра хода выполнения. Уделите немного времени, чтобы просмотреть наш прогресс в браузере. Как показано на рисунке 13, каждая строка отрисовывается с помощью , ItemTemplate
который содержит интерфейс редактирования ячейки.
Рис. 13. Каждая строка GridView редактируется (щелкните для просмотра полноразмерного изображения)
На этом этапе необходимо решить несколько незначительных проблем форматирования. Во-первых UnitPrice
, обратите внимание, что значение содержит четыре десятичные точки. Чтобы устранить эту проблему, вернитесь к шаблону UnitPrice
TemplateField и ItemTemplate
в смарт-теге TextBox щелкните ссылку Изменить DataBindings. Затем укажите, что Text
свойство должно быть отформатировано в виде числа.
Рис. 14. Форматирование Text
свойства в виде числа
Во-вторых, разместите флажок по центру в столбце Discontinued
(вместо выравнивания по левому краю). Щелкните Изменить столбцы в смарт-теге GridView и выберите Discontinued
TemplateField в списке полей в левом нижнем углу. Выполните детализацию ItemStyle
и задайте HorizontalAlign
для свойства значение Center, как показано на рис. 15.
Рис. 15. Центрирование Discontinued
checkBox
Затем добавьте элемент управления ValidationSummary на страницу и задайте для его ShowMessageBox
свойства значение true
, а для свойства ShowSummary
— значение false
. Кроме того, добавьте веб-элементы управления Button, которые при нажатии будут обновлять изменения, внесенные пользователем. В частности, добавьте два веб-элемента управления Button, один над GridView и один под ним, установив для обоих свойств элемента управления Text
значение Update Products .
Так как интерфейс редактирования GridView определен в шаблонах TemplateFields ItemTemplate
, EditItemTemplate
они являются лишними и могут быть удалены.
После внесения указанных выше изменений форматирования, добавления элементов управления Кнопка и удаления ненужных 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 показана эта страница при просмотре в браузере после добавления веб-элементов управления "Кнопка" и изменения форматирования.
Рис. 16. Страница теперь включает две кнопки обновления продуктов (щелкните для просмотра полноразмерного изображения)
Шаг 5. Обновление продуктов
Когда пользователь посещает эту страницу, он вносит изменения и нажимает одну из двух кнопок Обновить продукты. На этом этапе нам нужно каким-то образом сохранить введенные пользователем значения для каждой ProductsDataTable
строки в экземпляре, а затем передать их в метод BLL, который затем передает этот ProductsDataTable
экземпляр в метод DAL s UpdateWithTransaction
. Метод UpdateWithTransaction
, созданный в предыдущем руководстве, гарантирует, что пакет изменений будет обновлен как атомарная операция.
Создайте метод с именем BatchUpdate
in BatchUpdate.aspx.cs
и добавьте следующий код:
private void BatchUpdate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Find the ProductsRow instance in products that maps to gvRow
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsRow product = products.FindByProductID(productID);
if (product != null)
{
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products);
}
Этот метод начинается с получения всех продуктов обратно в с ProductsDataTable
помощью вызова метода BLL s GetProducts
. Затем он перечисляет коллекцию ProductGrid
GridViewRows
. Коллекция Rows
содержит экземпляр для каждой GridViewRow
строки, отображаемой в GridView. Так как отображается не более десяти строк на странице, коллекция GridView Rows
будет содержать не более десяти элементов.
Для каждой ProductID
строки извлекается из DataKeys
коллекции и выбирается соответствующий ProductsRow
объект из ProductsDataTable
. На четыре элемента управления ввода TemplateField ссылаются программными средствами, а их значения присваиваются свойствам ProductsRow
экземпляра. После того как значения каждой строки GridView использовались для обновления ProductsDataTable
, они передаются в метод BLL sUpdateWithTransaction
, который, как мы видели в предыдущем руководстве, просто вызывает метод DAL.UpdateWithTransaction
Алгоритм пакетного обновления, используемый в этом руководстве, обновляет каждую строку в ProductsDataTable
, соответствующую строке в GridView, независимо от того, были ли изменены сведения о продукте. Хотя такие слепые обновления обычно не являются проблемой производительности, они могут привести к излишним записям при повторном аудите изменений в таблице базы данных. В учебнике Выполнение пакетной Обновления мы изучили интерфейс пакетного обновления с помощью DataList и добавили код, который будет обновлять только те записи, которые были фактически изменены пользователем. При необходимости вы можете использовать методы из раздела Выполнение пакетной Обновления для обновления кода в этом руководстве.
Примечание
При привязке источника данных к GridView с помощью смарт-тега DataKeyNames
Visual Studio автоматически назначает значения первичного ключа источника данных свойству GridView. Если объект ObjectDataSource не был привязан к GridView с помощью смарт-тега GridView, как описано на шаге 1, необходимо вручную задать для свойства GridView DataKeyNames
значение ProductID, чтобы получить доступ ProductID
к значению каждой строки в DataKeys
коллекции.
Код, используемый в BatchUpdate
, аналогичен тому, который используется в методах UpdateProduct
BLL, main отличие заключается в том, что в UpdateProduct
методах из архитектуры извлекается только один ProductRow
экземпляр. Код, присваивающий свойства , является одинаковым ProductRow
между UpdateProducts
методами и кодом в цикле foreach
в BatchUpdate
, как и общий шаблон.
Для работы с этим руководством необходимо BatchUpdate
вызвать метод при нажатии любой из кнопок Обновить продукты. Создайте обработчики событий для Click
этих двух элементов управления Button и добавьте следующий код в обработчики событий:
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
Сначала выполняется вызов .BatchUpdate
Затем используется для внедрения Кода JavaScript, ClientScript property
в котором будет отображаться окно сообщений с текстом Продукты были обновлены.
Уделите немного времени, чтобы протестировать этот код. Перейдите BatchUpdate.aspx
в браузер, измените несколько строк и нажмите одну из кнопок Обновить продукты. При условии отсутствия ошибок проверки входных данных должно появиться окно сообщения с текстом Продукты были обновлены. Чтобы проверить атомарность обновления, попробуйте добавить случайное CHECK
ограничение, например ограничение, запрещающее UnitPrice
значения 1234,56. Затем в BatchUpdate.aspx
измените количество записей, присвоив одному из значений продукта UnitPrice
запрещенное значение ( 1234,56 ). Это приведет к ошибке при нажатии кнопки Обновить продукты с другими изменениями во время пакетной операции, откатом к исходным значениям.
АльтернативныйBatchUpdate
метод
Только BatchUpdate
что проверенный метод извлекает все продукты из метода BLL, GetProducts
а затем обновляет только те записи, которые отображаются в GridView. Этот подход идеально подходит, если GridView не использует разбиение по страницам, но в этом случае в GridView могут быть сотни, тысячи или десятки тысяч продуктов, но только десять строк. В этом случае получение всех продуктов из базы данных только для изменения 10 из них является менее чем идеальным.
В таких ситуациях рекомендуется использовать следующий BatchUpdateAlternate
метод:
private void BatchUpdateAlternate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Create a new ProductRow instance
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsDataTable currentProductDataTable =
productsAPI.GetProductByProductID(productID);
if (currentProductDataTable.Rows.Count > 0)
{
Northwind.ProductsRow product = currentProductDataTable[0];
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
// Import the ProductRow into the products DataTable
products.ImportRow(product);
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products);
}
BatchMethodAlternate
Начинается с создания пустого ProductsDataTable
экземпляра с именем products
. Затем он выполняет шаги по коллекции GridView Rows
и для каждой строки получает сведения о конкретном продукте с помощью метода BLL s GetProductByProductID(productID)
. Свойства извлеченного экземпляра ProductsRow
обновляются так же, как BatchUpdate
и , но после обновления строки он импортируется в products``ProductsDataTable
с помощью метода DataTable.ImportRow(DataRow)
foreach
После завершения products
цикла содержит по одному ProductsRow
экземпляру для каждой строки в GridView. Так как каждый из ProductsRow
экземпляров был добавлен products
в (а не обновлен), если мы слепо передадим его UpdateWithTransaction
методу ProductsTableAdapter
, будет пытаться вставить каждую из записей в базу данных. Вместо этого необходимо указать, что каждая из этих строк была изменена (не добавлена).
Это можно сделать, добавив новый метод в BLL с именем UpdateProductsWithTransaction
. UpdateProductsWithTransaction
, как показано ниже, задает каждому экземпляру ProductsRow
ProductsDataTable
в объекте значение Modified
, а затем передает ProductsDataTable
методу DAL.UpdateWithTransaction
RowState
public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
// Mark each product as Modified
products.AcceptChanges();
foreach (Northwind.ProductsRow product in products)
product.SetModified();
// Update the data via a transaction
return UpdateWithTransaction(products);
}
Сводка
GridView предоставляет встроенные возможности редактирования строк, но не поддерживает создание полностью редактируемых интерфейсов. Как мы видели в этом руководстве, такие интерфейсы возможны, но требуют немного работы. Чтобы создать Элемент GridView, в котором можно редактировать каждую строку, необходимо преобразовать поля GridView в TemplateFields и определить интерфейс редактирования в элементах ItemTemplate
. Кроме того, на страницу необходимо добавить веб-элементы управления Update All -type Button отдельно от GridView. Обработчики событий Button Click
должны перечислить коллекцию GridView Rows
, сохранить изменения в ProductsDataTable
и передать обновленные сведения в соответствующий метод BLL.
В следующем руководстве мы рассмотрим, как создать интерфейс для пакетного удаления. В частности, каждая строка GridView будет содержать флажок, а вместо кнопок "Обновить все" будут кнопки "Удалить выбранные строки".
Счастливого программирования!
Об авторе
Скотт Митчелл( Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часах. Он может быть доступен в mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.
Особая благодарность
Эта серия учебников была рассмотрена многими полезными рецензентами. Ведущими рецензентами этого руководства были Тереса Мерфи и Дэвид Суру. Хотите просмотреть предстоящие статьи MSDN? Если да, опустите мне строку на mitchell@4GuysFromRolla.com.