Поделиться через


Выполнение пакетных обновлений (VB)

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

Скачать в формате PDF

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

Введение

В предыдущем руководстве мы рассмотрели, как создать dataList уровня элемента. Как и стандартный редактируемый GridView, каждый элемент в DataList включал кнопку "Изменить", которая при щелчке сделает элемент редактируемым. Хотя редактирование на уровне элемента хорошо подходит для данных, которые обновляются только иногда, некоторые сценарии использования требуют, чтобы пользователь редактировал много записей. Если пользователю нужно изменить десятки записей и принудительно нажать кнопку "Изменить", внести изменения и нажать кнопку "Обновить" для каждой из них, количество щелчков может препятствовать ее производительности. В таких ситуациях лучше предоставить полностью редактируемый dataList, где все его элементы находятся в режиме редактирования и чьи значения можно изменить, нажав кнопку "Обновить все" на странице (см. рис. 1).

Каждый элемент в полно редактируемом списке данных можно изменить

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

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

Шаг 1. Создание редактируемого пользовательского интерфейса в элементе ItemTemplate DataList

В предыдущем руководстве, где мы создадим стандартный редактируемый dataList уровня элементов, мы использовали два шаблона:

  • ItemTemplate содержит пользовательский интерфейс только для чтения (веб-элементы управления label для отображения имени и цены каждого продукта).
  • EditItemTemplate содержит пользовательский интерфейс режима редактирования (два веб-элемента управления TextBox).

Свойство DataList EditItemIndex определяет, что DataListItem (если таковое) отрисовывается с помощью EditItemTemplate. В частности, DataListItem значение которого ItemIndex соответствует свойству DataList EditItemIndex , отображается с помощью EditItemTemplate. Эта модель хорошо работает, если только один элемент можно изменять одновременно, но разбивается при создании полно редактируемого списка данных.

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

Начните с открытия BatchUpdate.aspx страницы, добавьте элемент управления DataList и задайте для его свойства Suppliersзначение ID . В смарт-теге DataList выберите новый элемент управления ObjectDataSource с именем SuppliersDataSource.

Создание объекта ObjectDataSource с именем SuppliersDataSource

Рис. 2. Создание объекта ObjectDataSource С именем (SuppliersDataSourceщелкните, чтобы просмотреть изображение полного размера)

Настройте ObjectDataSource для получения данных с помощью SuppliersBLL метода класса GetSuppliers() (см. рис. 3). Как и в предыдущем руководстве, а не обновите сведения о поставщике с помощью ObjectDataSource, мы будем работать непосредственно с уровнем бизнес-логики. Поэтому в раскрывающемся списке (Нет) на вкладке UPDATE (см. рис. 4).

Получение сведений о поставщике с помощью метода GetSuppliers()

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

Задайте для раскрывающегося списка значение (Нет) на вкладке UPDATE

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

После завершения работы мастера Visual Studio автоматически создает dataList для ItemTemplate отображения каждого поля данных, возвращаемого источником данных в веб-элементе управления Label. Необходимо изменить этот шаблон, чтобы он предоставлял интерфейс редактирования. Его ItemTemplate можно настроить с помощью конструктора с помощью параметра "Изменить шаблоны" из смарт-тега DataList или непосредственно с помощью декларативного синтаксиса.

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

<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
    DataSourceID="SuppliersDataSource">
    <ItemTemplate>
        <h4><asp:Label ID="CompanyNameLabel" runat="server"
            Text='<%# Eval("CompanyName") %>' /></h4>
        <table border="0">
            <tr>
                <td class="SupplierPropertyLabel">Address:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Address" runat="server"
                        Text='<%# Eval("Address") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">City:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="City" runat="server"
                        Text='<%# Eval("City") %>' />
                </td>
            </tr>
            <tr>
                <td class="SupplierPropertyLabel">Country:</td>
                <td class="SupplierPropertyValue">
                    <asp:TextBox ID="Country" runat="server"
                        Text='<%# Eval("Country") %>' />
                </td>
            </tr>
        </table>
        <br />
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>

Примечание.

Как и в предыдущем руководстве, dataList в этом руководстве должен иметь состояние представления.

ItemTemplate В i m using two new CSS classSupplierPropertyLabel, and , которые были добавлены в Styles.css класс и SupplierPropertyValueнастроены для использования одинаковых параметров стиля, что ProductPropertyLabel и ProductPropertyValue классы CSS.

.ProductPropertyLabel, .SupplierPropertyLabel
{
    font-weight: bold;
    text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
    padding-right: 35px;
}

После внесения этих изменений посетите эту страницу через браузер. Как показано на рисунке 5, каждый элемент DataList отображает имя поставщика в виде текста и использует textBoxes для отображения адреса, города и страны или региона.

Каждый поставщик в DataList доступен для редактирования

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

Шаг 2. Добавление кнопки "Обновить все"

Хотя каждый поставщик на рис. 5 имеет свой адрес, город и поля страны или региона, отображаемые в текстовом поле, в настоящее время нет кнопки "Обновить". Вместо того, чтобы кнопка "Обновить" для каждого элемента с полной редактируемой функцией DataLists обычно существует одна кнопка "Обновить все" на странице, которая при нажатии кнопки обновляет все записи в DataList. В этом руководстве давайте добавим две кнопки "Обновить все" в верхней части страницы и один в нижней части (хотя нажатие одной кнопки будет иметь одинаковый эффект).

Сначала добавьте веб-элемент управления Button над DataList и задайте для него значение ID свойства UpdateAll1. Затем добавьте второй веб-элемент управления Button под DataList, задав для нее значение ID UpdateAll2. Text Задайте свойства для двух кнопок, чтобы обновить все. Наконец, создайте обработчики событий для обоих событий Button Click . Вместо дедупликации логики обновления в каждом обработчике событий давайте рефакторингу этой логики на третий метод, UpdateAllSupplierAddressesпри этом обработчики событий просто вызывают этот третий метод.

Protected Sub UpdateAll1_Click(sender As Object, e As EventArgs) _
    Handles UpdateAll1.Click
    UpdateAllSupplierAddresses()
End Sub
Protected Sub UpdateAll2_Click(sender As Object, e As EventArgs) _
    Handles UpdateAll2.Click
    UpdateAllSupplierAddresses()
End Sub
Private Sub UpdateAllSupplierAddresses()
    ' TODO: Write code to update _all_ of the supplier addresses in the DataList
End Sub

На рисунке 6 показана страница после добавления кнопок "Обновить все".

На страницу добавлены две кнопки обновления всех

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

Шаг 3. Обновление всех сведений об адресах поставщиков

Со всеми элементами DataList, отображающими интерфейс редактирования и добавлением кнопок "Обновить все", все, что остается, записывает код для выполнения пакетного обновления. В частности, необходимо выполнить цикл по элементам DataList и вызвать SuppliersBLL метод класса UpdateSupplierAddress для каждого из них.

Коллекция DataListItem экземпляров, которые составят DataList, можно получить через свойство DataListItems. Со ссылкой на DataListItemколлекцию можно получить соответствующие SupplierID данные из DataKeys коллекции и программно ссылаться на веб-элементы управления TextBox в ItemTemplate следующем коде:

Private Sub UpdateAllSupplierAddresses()
    ' Create an instance of the SuppliersBLL class
    Dim suppliersAPI As New SuppliersBLL()
    ' Iterate through the DataList's items
    For Each item As DataListItem In Suppliers.Items
        ' Get the supplierID from the DataKeys collection
        Dim supplierID As Integer = Convert.ToInt32(Suppliers.DataKeys(item.ItemIndex))
        ' Read in the user-entered values
        Dim address As TextBox = CType(item.FindControl("Address"), TextBox)
        Dim city As TextBox = CType(item.FindControl("City"), TextBox)
        Dim country As TextBox = CType(item.FindControl("Country"), TextBox)
        Dim addressValue As String = Nothing, _
            cityValue As String = Nothing, _
            countryValue As String = Nothing
        If address.Text.Trim().Length > 0 Then
            addressValue = address.Text.Trim()
        End If
        If city.Text.Trim().Length > 0 Then
            cityValue = city.Text.Trim()
        End If
        If country.Text.Trim().Length > 0 Then
            countryValue = country.Text.Trim()
        End If
        ' Call the SuppliersBLL class's UpdateSupplierAddress method
        suppliersAPI.UpdateSupplierAddress _
            (supplierID, addressValue, cityValue, countryValue)
    Next
End Sub

Когда пользователь щелкает одну из кнопок Update All, UpdateAllSupplierAddresses метод выполняет итерацию по каждому DataListItem в Suppliers DataList и вызывает SuppliersBLL метод класса UpdateSupplierAddress , передавая соответствующие значения. Не введенное значение для адреса, города или страны или региона — это значение Nothing UpdateSupplierAddress (а не пустая строка), которое приводит к базе данных NULL для полей базовой записи.

Примечание.

В качестве улучшения может потребоваться добавить веб-элемент управления метки состояния на страницу, которая предоставляет некоторое сообщение подтверждения после выполнения пакетного обновления.

Обновление только тех адресов, которые были изменены

Алгоритм пакетного обновления, используемый в этом руководстве, вызывает UpdateSupplierAddress метод для каждого поставщика в DataList независимо от того, были ли изменены сведения об адресе. Хотя такие слепые обновления обычно не являются проблемой производительности, они могут привести к лишним записям, если вы выполняете аудит изменений в таблице базы данных. Например, если вы используете триггеры для записи всех UPDATE s в Suppliers таблицу аудита, каждый раз, когда пользователь нажимает кнопку "Обновить все", новая запись аудита будет создана для каждого поставщика в системе независимо от того, вносил ли пользователь какие-либо изменения.

Классы dataTable и DataAdapter ADO.NET предназначены для поддержки пакетных обновлений, в которых только изменены, удалены и новые записи приводят к любому обмену данными с базой данных. Каждая строка в DataTable имеет RowState свойство , указывающее, была ли строка добавлена в DataTable, удалена из нее, изменена или остается неизменной. При первоначальном заполнении DataTable все строки помечаются без изменений. Изменение значения любого столбца строки помечает строку как измененную.

SuppliersBLL В классе мы обновляем сведения об адресе указанного поставщика, сначала считывая запись одного поставщика в объектSuppliersDataTable, а затем задали AddressCityзначения столбцов, Country используя следующий код:

Public Function UpdateSupplierAddress _
    (supplierID As Integer, address As String, city As String, country As String) _
    As Boolean
    Dim suppliers As Northwind.SuppliersDataTable = _
        Adapter.GetSupplierBySupplierID(supplierID)
    If suppliers.Count = 0 Then
        ' no matching record found, return false
        Return False
    Else
        Dim supplier As Northwind.SuppliersRow = suppliers(0)
        If address Is Nothing Then
            supplier.SetAddressNull()
        Else
            supplier.Address = address
        End If
        If city Is Nothing Then
            supplier.SetCityNull()
        Else
            supplier.City = city
        End If
        If country Is Nothing Then
            supplier.SetCountryNull()
        Else
            supplier.Country = country
        End If
        ' Update the supplier Address-related information
        Dim rowsAffected As Integer = Adapter.Update(supplier)
        ' Return true if precisely one row was updated, otherwise false
        Return rowsAffected = 1
    End If
End Function

Этот код наивно назначает значения переданного адреса, города и страны или региона SuppliersRow SuppliersDataTable в зависимости от того, изменились ли значения. Эти изменения приводят SuppliersRow к тому, что свойство s RowState помечается как измененное. Когда вызывается метод уровня Update доступа к данным, он видит, что SupplierRow он был изменен и поэтому отправляет UPDATE команду в базу данных.

Представьте себе, что мы добавили код в этот метод, чтобы назначить только переданные значения адреса, города и страны или региона, если они отличаются от существующих значений SuppliersRow . В случае, если адрес, город и страна или регион совпадают с существующими данными, изменения не будут вноситься, и они SupplierRow RowState будут оставлены без изменений. Чистый результат заключается в том, что при вызове метода DAL Update вызов базы данных не будет выполнен, так как SuppliersRow он не был изменен.

Чтобы принять это изменение, замените инструкции, которые слепо назначают переданные адреса, города и страны или региона следующим кодом:

' Only assign the values to the SupplierRow's column values if they differ
If address Is Nothing AndAlso Not supplier.IsAddressNull() Then
    supplier.SetAddressNull()
ElseIf (address IsNot Nothing AndAlso supplier.IsAddressNull) _
    OrElse (Not supplier.IsAddressNull() AndAlso _
                String.Compare(supplier.Address, address) <> 0) Then
    supplier.Address = address
End If
If city Is Nothing AndAlso Not supplier.IsCityNull() Then
    supplier.SetCityNull()
ElseIf (city IsNot Nothing AndAlso supplier.IsCityNull) _
    OrElse (Not supplier.IsCityNull() AndAlso _
                String.Compare(supplier.City, city) <> 0) Then
    supplier.City = city
End If
If country Is Nothing AndAlso Not supplier.IsCountryNull() Then
    supplier.SetCountryNull()
ElseIf (country IsNot Nothing AndAlso supplier.IsCountryNull) _
    OrElse (Not supplier.IsCountryNull() AndAlso _
                String.Compare(supplier.Country, country) <> 0) Then
    supplier.Country = country
End If

В этом добавленном коде метод DAL Update отправляет UPDATE инструкцию в базу данных только для тех записей, значения которых изменились.

Кроме того, можно отслеживать наличие различий между переданными полями адресов и данными базы данных, а если нет, просто обойти вызов метода DAL Update . Этот подход работает хорошо, если используется прямой метод базы данных, так как прямой метод базы данных не передает SuppliersRow экземпляр, который RowState можно проверить, чтобы определить, требуется ли вызов базы данных.

Примечание.

UpdateSupplierAddress При каждом вызове метода вызывается в базу данных для получения сведений об обновленной записи. Затем при наличии изменений в данных выполняется еще один вызов базы данных для обновления строки таблицы. Этот рабочий процесс можно оптимизировать, создав перегрузку UpdateSupplierAddress метода, которая принимает EmployeesDataTable экземпляр со всеми изменениями на BatchUpdate.aspx странице. Затем он может вызвать базу данных, чтобы получить все записи из Suppliers таблицы. Затем можно перечислить два набора результатов и обновить только те записи, в которых произошли изменения.

Итоги

В этом руководстве мы узнали, как создать полностью редактируемый Список данных, что позволяет пользователю быстро изменять сведения об адресе для нескольких поставщиков. Мы начали с определения интерфейса редактирования веб-элемента управления TextBox для адреса поставщика, города и страны или региона в dataList ItemTemplate. Затем мы добавили кнопки Update All выше и ниже DataList. После внесения изменений и нажатия одной из кнопок Update All перечисляются и DataListItem выполняется вызов SuppliersBLL метода класса UpdateSupplierAddress .

Счастливое программирование!

Об авторе

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

Особое спасибо

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