Пакетное обновление (VB)

по Скотт Митчелл

Скачать код или скачать PDF

Узнайте, как обновить несколько записей базы данных за одну операцию. На уровне пользовательского интерфейса создается элемент управления GridView, в котором каждая строка является редактируемой. На уровне доступа к данным мы переносите несколько операций обновления в рамках транзакции, чтобы гарантировать успешность всех обновлений или откат всех обновлений.

Введение

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

В этом учебнике будет построен элемент управления GridView, в котором каждая строка является редактируемой (см. рис. 1). Поскольку каждая строка подготавливается к просмотру в интерфейсе редактирования, нет необходимости в столбцах кнопок Правка, обновить и Отмена. Вместо этого на странице есть две кнопки обновить продукты, которые при нажатии перечисляют строки GridView и обновляют базу данных.

, что каждая строка в GridView является редактируемой

Рис. 1. Каждая строка в GridView является редактируемой (щелкните, чтобы просмотреть изображение с полным размером)

Давайте приступим к работе!

Note

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

Изучение шагов, позволяющих вносить изменения в все строки GridView

Как обсуждалось в обзоре руководства по вставке, обновлению и удалению данных , GridView предлагает встроенную поддержку редактирования базовых данных для отдельных строк. На внутреннем уровне элемент управления GridView замещает строку, которую можно редактировать с помощью свойстваEditIndex. Так как GridView привязан к источнику данных, он проверяет каждую строку на предмет того, что индекс строки равен значению EditIndex. В этом случае поля строки отображаются с помощью своих интерфейсов редактирования. Для BoundFields интерфейс редактирования — это текстовое поле, которому свойству Text присваивается значение поля данных, заданное свойством BoundField DataField. Для полей TemplateField вместо ItemTemplateиспользуется EditItemTemplate.

Помните, что рабочий процесс редактирования запускается, когда пользователь нажимает кнопку изменить строку. Это вызывает обратную передачу, задает для свойства EditIndex GridView s значение индекса clickd Row, а затем повторно привязывает данные к сетке. При нажатии кнопки "Отмена" в случае обратной передачи EditIndex присваивается значение -1 перед повторной привязкой данных к сетке. Так как GridView-строки в начале индексирования начинаются с нуля, установка EditIndex в -1 приводит к отображению GridView в режиме только для чтения.

Свойство EditIndex хорошо подходит для редактирования отдельных строк, но не предназначено для пакетного редактирования. Чтобы сделать весь элемент GridView доступным для редактирования, необходимо, чтобы каждая строка отображалась с помощью интерфейса правки. Самый простой способ сделать это — создать место, где каждое редактируемое поле реализуется как TemplateField с интерфейсом правки, определенным в ItemTemplate.

В следующих нескольких шагах мы создадим полностью редактируемый элемент управления GridView. На этапе 1 мы начнем с создания GridView и его ObjectDataSource и преобразуйте его BoundFields и CheckBoxField в полей TemplateField. В шагах 2 и 3 мы перейдем интерфейсы редактирования из полей TemplateField EditItemTemplate s в их ItemTemplate s.

Шаг 1. Отображение сведений о продукте

Прежде чем беспокоиться о создании элемента управления GridView, где доступны строки для редактирования, начнем с простого отображения сведений о продукте. Откройте страницу BatchUpdate.aspx в папке BatchData и перетащите элемент управления GridView с панели инструментов в конструктор. Установите ID GridView s ProductsGrid и, выбрав его смарт-тег, привяжите его к новому ObjectDataSource с именем ProductsDataSource. Настройте ObjectDataSource для извлечения данных из GetProducts метода ProductsBLL классов.

настроить ObjectDataSource для использования класса ProductsBLL

Рис. 2. Настройка ObjectDataSource для использования класса ProductsBLL (щелкните, чтобы просмотреть изображение с полным размером)

получения данных о продуктах с помощью метода Products

Рис. 3. получение данных о продукте с помощью метода GetProducts (щелкните, чтобы просмотреть изображение с полным размером)

Как и в GridView, функции изменения ObjectDataSource предназначены для работы с каждым строкой. Чтобы обновить набор записей, необходимо написать фрагмент кода в классе кода программной части ASP.NET Page s, который пакетируют данные и передает их BLL. Поэтому в раскрывающихся списках на вкладках "Обновить", "вставить" и "Удалить" выберите значение (нет). Нажмите кнопку Готово, чтобы завершить работу с мастером.

установить в раскрывающихся списках на вкладках обновления, вставки и удаления значение (нет)

Рис. 4. Установка раскрывающихся списков на вкладках обновления, вставки и удаления в (нет) (щелкните, чтобы просмотреть изображение с полным размером)

После завершения работы мастера настройки источника данных декларативная разметка ObjectDataSource s должна выглядеть следующим образом:

<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 для первых трех полей на продукты, категорию и цену соответственно. Наконец, установите флажки Включить разбиение по страницам и включить сортировку в смарт-теге GridView s.

На этом этапе GridView имеет три BoundFields (ProductName, CategoryNameи UnitPrice) и CheckBoxField (Discontinued). Необходимо преобразовать эти четыре поля в полей TemplateField, а затем переместить интерфейс редактирования из TemplateField s EditItemTemplate в ItemTemplate.

Note

Мы изучили создание и настройку полей TemplateField в руководстве по настройке интерфейса изменения данных . Мы рассмотрим шаги по преобразованию BoundFields и CheckBoxField в полей TemplateField и определении их интерфейсов редактирования в ItemTemplate s, но если вы захотите или потребуете обновления, не сможете вернуться к предыдущему руководству.

Из смарт-тега GridView s щелкните ссылку изменить столбцы, чтобы открыть диалоговое окно поля. Затем выберите каждое поле и щелкните преобразовать это поле в ссылку TemplateField.

Преобразование существующих BoundFields и CheckBoxField в полей TemplateField

Рис. 5. Преобразование существующих BoundFields и CheckBoxField в полей TemplateField

Теперь, когда каждое поле является TemplateField, мы перейдем к перемещению интерфейса редактирования из EditItemTemplate s в ItemTemplate s.

Шаг 2. СозданиеProductName,UnitPriceиDiscontinuedинтерфейсов редактирования

Создание ProductName, UnitPriceи Discontinued интерфейсов редактирования является темой этого шага и довольно проста, так как каждый интерфейс уже определен в EditItemTemplateTemplateField s. Создание интерфейса редактирования CategoryName является немного более сложным, поскольку необходимо создать DropDownList для применимых категорий. Этот CategoryName интерфейс редактирования разрешается на шаге 3.

Давайте начнем с ProductName TemplateField. Щелкните ссылку Edit Templates (изменить шаблоны) в смарт-теге GridView s и перейдите к ProductName TemplateField s EditItemTemplate. Выберите текстовое поле, скопируйте его в буфер обмена и вставьте в ProductName TemplateField s ItemTemplate. Измените для свойства ID TextBox значение ProductName.

Затем добавьте RequiredFieldValidator в ItemTemplate, чтобы гарантировать, что пользователь предоставит значение для каждого названия продукта. Задайте для свойства ControlToValidate значение ProductName, для свойства ErrorMessage необходимо указать имя продукта. и свойство Text для *. После внесения этих дополнений в ItemTemplateэкран должен выглядеть примерно так, как показано на рис. 6.

TemplateField ProductName теперь включает в себя текстовое поле и RequiredFieldValidator

Рис. 6. ProductName TemplateField теперь содержит текстовое поле и RequiredFieldValidator (щелкните, чтобы просмотреть изображение с полным размером)

Для интерфейса редактирования UnitPrice Начните с копирования текстового поля из EditItemTemplate в ItemTemplate. Затем поместите $ перед текстовым полем и задайте для свойства ID значение UnitPrice, а для свойства Columns — значение 8.

Также добавьте объект CompareValidator в ItemTemplate UnitPrice s, чтобы убедиться, что значение, указанное пользователем, является допустимым значением валюты, которое больше или равно $0,00. Задайте для свойства ControlToValidate проверяющего элемента управления значение UnitPrice, для свойства ErrorMessage необходимо ввести допустимое значение валюты. Не указывайте символы валют., свойство Text для *, его свойство Type для Currency, свойство Operator в GreaterThanEqual, а свойство ValueToCompare — в значение 0.

добавить объект CompareValidator для обеспечения того, что указанная цена является неотрицательным значением валюты

Рис. 7. Добавление элемента CompareValidator для обеспечения того, что указанная цена является неотрицательным значением валюты (щелкните, чтобы просмотреть изображение с полным размером)

Для Discontinued TemplateField можно использовать флажок, уже определенный в ItemTemplate. Просто задайте для его ID значение больше, а для свойства Enabled — значение True.

Шаг 3. Создание интерфейса редактированияCategoryName

Интерфейс редактирования в CategoryName TemplateField s EditItemTemplate содержит текстовое поле, в котором отображается значение поля данных CategoryName. Необходимо заменить его на DropDownList, в котором перечислены возможные категории.

Note

Руководство по настройке интерфейса изменения данных содержит более подробное и полное описание настройки шаблона для включения DropDownList, а не текстового поля. Хотя приведенные здесь действия завершены, они представлены кратко. Более подробные сведения о создании и настройке DropDownList см. в разделе Настройка интерфейса изменения данных .

Перетащите DropDownList с панели элементов на CategoryName TemplateField s ItemTemplate, установив для его ID значение Categories. На этом этапе мы обычно определяем источник данных элементов управления DropDownList s через смарт-тег, создавая новый элемент управления ObjectDataSource. Однако это приведет к добавлению ObjectDataSource в ItemTemplate, что приведет к созданию экземпляра ObjectDataSource для каждой строки GridView. Вместо этого давайте создадим элемент управления ObjectDataSource за пределами GridView s полей TemplateField. Завершите редактирование шаблона и перетащите элемент управления ObjectDataSource с панели элементов в конструктор под ProductsDataSource ObjectDataSource. Присвойте новому элементу ObjectDataSource имя CategoriesDataSource и настройте его для использования метода CategoriesBLL класса s GetCategories.

настроить ObjectDataSource для использования класса CategoriesBLL

Рис. 8. Настройка ObjectDataSource для использования класса CategoriesBLL (щелкните, чтобы просмотреть изображение с полным размером)

получения данных категории с помощью метода Categories

Рис. 9. получение данных категории с помощью метода GetCategories (щелкните, чтобы просмотреть изображение с полным размером)

Так как этот элемент ObjectDataSource используется только для получения данных, установите в раскрывающихся списках на вкладках обновление и удаление значение (нет). Нажмите кнопку Готово, чтобы завершить работу с мастером.

установить в раскрывающихся списках на вкладках обновить и удалить значение (нет)

Рис. 10. Установка в раскрывающихся списках на вкладках "Обновить" и "Удалить" (нет) (щелкните, чтобы просмотреть изображение с полным размером)

После завершения работы мастера декларативная разметка CategoriesDataSource s должна выглядеть следующим образом:

<asp:ObjectDataSource ID="CategoriesDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

После создания и настройки CategoriesDataSource вернитесь к CategoryName TemplateField s ItemTemplate а в смарт-теге DropDownList s щелкните ссылку Выбор источника данных. В мастере настройки источника данных выберите параметр CategoriesDataSource из первого раскрывающегося списка и выберите использование CategoryName для вывода и CategoryID в качестве значения.

привязать DropDownList к CategoriesDataSource

Рис. 11. Привязка DropDownList к CategoriesDataSource (щелкните, чтобы просмотреть изображение с полным размером)

На этом этапе Categories DropDownList перечисляет все категории, но не автоматически выбирает соответствующую категорию для продукта, привязанного к строке GridView. Для этого необходимо установить Categories DropDownList SelectedValue в значение Product s CategoryID. Щелкните ссылку Edit DataBindings (Редактировать привязки данных) в смарт-теге DropDownList и свяжите свойство SelectedValue с полем данных CategoryID, как показано на рис. 12.

Привяжите значение CategoryID продукта к свойству DropDownList SelectedValue

Рис. 12. Привязка значения Product CategoryID к свойству SelectedValue DropDownList

Последняя проблема остается: Если для продукта не задано значение CategoryID, инструкция DataBinding в 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="">--выберите один--атрибут Value явно задан пустой строкой. Ознакомьтесь с руководством по настройке интерфейса изменения данных , чтобы получить более полное представление о том, почему этот дополнительный элемент DropDownList необходим для обработки NULL случае, и зачем назначение свойства Value пустой строке является обязательным.

Note

Здесь есть потенциальная ошибка производительности и масштабируемости, которую стоит упомянуть. Поскольку каждая строка содержит элемент управления DropDownList, использующий CategoriesDataSource в качестве источника данных, метод CategoriesBLL класса s GetCategories будет называться n раз на страницу посещения страницы, где n — число строк в GridView. Эти n вызовов GetCategories приводят к появлению n запросов к базе данных. Это влияние на базу данных можно уменьшить путем кэширования возвращенных категорий либо в кэше запросов, либо с помощью уровня кэширования с использованием зависимости кэширования SQL или с очень коротким сроком действия на основе времени. Дополнительные сведения о параметре кэширования для каждого запроса см. в разделе HttpContext.Items хранилище кэша для каждого запроса.

Шаг 4. Завершение интерфейса редактирования

Мы внесли ряд изменений в шаблоны GridView s без приостановки для просмотра хода выполнения. Уделите время для просмотра хода выполнения в браузере. Как показано на рис. 13, каждая строка отображается с помощью ItemTemplate, которая содержит интерфейс редактирования ячеек.

, что каждая строка GridView доступна для редактирования

Рис. 13. Каждая строка GridView доступна для редактирования (щелкните, чтобы просмотреть изображение с полным размером)

На этом этапе следует соблюдать несколько проблем, связанных с форматированием. Сначала обратите внимание, что значение UnitPrice содержит четыре десятичных знака. Чтобы устранить эту проблему, вернитесь к UnitPrice TemplateField s ItemTemplate и в смарт-теге TextBox щелкните ссылку изменить привязки к данным. Затем укажите, что свойство Text должно быть отформатировано как число.

Форматирование свойства Text как числа

Рис. 14. форматирование свойства Text в виде числа

Во-вторых, давайте разберем флажок в столбце Discontinued (вместо того, чтобы он был выровнен по левому краю). Щелкните Edit Columns (изменить столбцы) в смарт-теге GridView s и выберите Discontinued TemplateField из списка полей в левом нижнем углу. Детализируйте углублением ItemStyle и задайте для свойства HorizontalAlign значение Center, как показано на рис. 15.

Центрирование снятого флажка

Рис. 15. центрирование флажка Discontinued

Затем добавьте на страницу элемент управления ValidationSummary и задайте для его свойства ShowMessageBox значение True, а для свойства ShowSummary значение False. Также добавьте веб-элементы управления "Кнопка", которые при нажатии обновит изменения пользователя. В частности, добавьте два веб-элемента управления "Кнопка", один из которых находится над GridView, и один под ним, устанавливая оба элемента управления, Text свойства для обновления продуктов.

Поскольку интерфейс редактирования GridView s определен в его полей TemplateField ItemTemplate s, EditItemTemplate s являются избыточными и могут быть удалены.

После внесения перечисленных выше изменений форматирования, добавления элементов управления "Кнопка" и удаления ненужных EditItemTemplate s декларативный синтаксис страниц должен выглядеть следующим образом:

<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 в 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 с помощью вызова метода GetProducts BLL. Затем выполняется перечисление коллекции ProductGrid GridView s Rows. Коллекция Rows содержит экземплярGridViewRow для каждой строки, отображаемой в GridView. Так как мы видим не более десяти строк на странице, Rows коллекция GridView s будет содержать не более десяти элементов.

Для каждой строки, ProductID извлеченной из коллекции DataKeys и выбрана соответствующая ProductsRow из ProductsDataTable. На четыре элемента управления вводом TemplateField программными ссылками, а также их значения, назначенные свойствам экземпляра ProductsRow. После того, как для обновления ProductsDataTableиспользуются все значения строк GridView, они передавались методу UpdateWithTransaction BLL, который, как мы видели в предыдущем руководстве, просто вызывает метод DAL s UpdateWithTransaction.

Алгоритм пакетного обновления, используемый в этом руководстве, обновляет каждую строку в ProductsDataTable, соответствующую строке в GridView, независимо от того, изменились ли сведения о продукте. Хотя подобные обновления, как правило, не являются проблемой с производительностью, они могут привести к излишним записям при повторном аудите изменений в таблице базы данных. В учебнике выполнение пакетных обновлений мы изучили интерфейс обновления пакетной службы с помощью DataList и добавили код, который будет обновлять только те записи, которые фактически были изменены пользователем. При необходимости вы можете использовать методы выполнения пакетных обновлений для обновления кода в этом руководстве.

Note

При привязке источника данных к GridView через его смарт-тег Visual Studio автоматически назначает значения первичного ключа (-ов) источника данных для свойства DataKeyNames GridView s. Если вы не привязали ObjectDataSource к GridView с помощью смарт-тега GridView s, как описано в шаге 1, необходимо вручную задать для свойства DataKeyNames GridView s значение ProductID, чтобы получить доступ к ProductIDному значению для каждой строки через коллекцию DataKeys.

Код, используемый в BatchUpdate, аналогичен тому, который использовался в методах UpdateProduct BLL, основное различие заключается в том, что в методах UpdateProduct извлекается только один экземпляр ProductRow из архитектуры. Код, который назначает свойства ProductRow, одинаков между методами UpdateProducts и кодом в цикле For Each в BatchUpdate, как и общий шаблон.

Для работы с этим руководством необходимо, чтобы метод BatchUpdate вызывался при нажатии любой из кнопок обновить продукты. Создайте обработчики событий для Click событий этих двух элементов управления "Кнопка" и добавьте следующий код в обработчики событий:

BatchUpdate()
ClientScript.RegisterStartupScript(Me.GetType(), "message", _
    "alert('The products have been updated.');", True)

Сначала выполняется вызов BatchUpdate. Затем свойствоClientScript используется для вставки JavaScript, который будет отображать MessageBox, считывающие продукты, которые были обновлены.

Протестируйте этот код, уделите минуту. Откройте BatchUpdate.aspx через браузер, измените несколько строк и нажмите одну из кнопок обновить продукты. Если нет ошибок проверки ввода, вы увидите MessageBox, считывающий продукты, которые были обновлены. Чтобы проверить атомарность обновления, рассмотрите возможность добавления случайного ограничения CHECK, например, которое запрещает UnitPrice значения 1234,56. Затем из BatchUpdate.aspxизмените несколько записей, установив для одного из них UnitPrice значение запрещено (1234,56). Это должно привести к ошибке при нажатии кнопки обновить продукты с другими изменениями во время отката пакетной операции к исходным значениям.

Альтернативный методBatchUpdate

Метод BatchUpdate, который мы только что проверили, извлекает все продукты из метода GetProducts BLL, а затем обновляет только те записи, которые отображаются в 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 s Rows и для каждой строки получается информация о продукте с помощью метода GetProductByProductID(productID) BLL. Свойства полученного экземпляра ProductsRow обновляются так же, как BatchUpdate, но после обновления строки она импортируется в products ProductsDataTable с помощью метода DataTable s ImportRow(DataRow).

После завершения цикла For Each products содержит один экземпляр ProductsRow для каждой строки в GridView. Так как каждый из ProductsRowных экземпляров был добавлен в products (вместо обновления), если они передаются в метод UpdateWithTransaction, ProductsTableAdapter попытается вставить каждую из записей в базу данных. Вместо этого необходимо указать, что каждая из этих строк была изменена (не добавлена).

Это можно сделать, добавив новый метод в BLL с именем UpdateProductsWithTransaction. UpdateProductsWithTransaction, показанный ниже, устанавливает RowState для каждого экземпляра ProductsRow в ProductsDataTable в Modified, а затем передает ProductsDataTable методу DAL s UpdateWithTransaction.

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 s в полей TemplateField и определить интерфейс редактирования в ItemTemplate s. Кроме того, на страницу должны быть добавлены веб-элементы управления для обновления всех типов, отделенные от GridView. Эти кнопки Click обработчикам событий необходимо перечислить коллекцию Rows GridView, сохранить изменения в ProductsDataTableи передать обновленные сведения в соответствующий метод BLL.

В следующем учебном курсе будет показано, как создать интерфейс для пакетного удаления. В частности, каждая строка GridView будет включать в себя флажок, а вместо кнопки Обновить все-типы будут выбраны кнопки Удалить выбранные строки.

Поздравляем с программированием!

Об авторе

Скотт Митчелл, автор семи книг по ASP/ASP. NET и основатель 4GuysFromRolla.com, работал с веб-технологиями Майкрософт с 1998. Скотт работает как независимый консультант, преподаватель и модуль записи. Его последняя книга — Sams обучать себя ASP.NET 2,0 за 24 часа. Он доступен по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Специальная благодарность

Эта серия руководств была рассмотрена многими полезными рецензентами. Потенциальные рецензенты для этого учебника были Терезой Мерфи и Дэвид суру. Хотите ознакомиться с моими будущими статьями MSDN? Если это так, расположите строку в mitchell@4GuysFromRolla.com.