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

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

Загрузить PDF-файл

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

Введение

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

На вкладке UPDATE задайте для Drop-Down List значение (Нет)

Рис. 4. Задайте для Drop-Down List значение (Нет) на вкладке ОБНОВЛЕНИЕ (щелкните для просмотра полноразмерного изображения)

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

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

<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 использую два новых класса CSS, SupplierPropertyLabel и SupplierPropertyValue, которые были добавлены в Styles.css класс и настроены для использования параметров стиля, что ProductPropertyLabel и ProductPropertyValue классы CSS.

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

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

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

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

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

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

Начните с добавления элемента управления Button Web над 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, можно получить через свойство DataList Items. С помощью ссылки на можно получить соответствующий DataListItemSupplierID объект из 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

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

Примечание

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

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

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

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

SuppliersBLL В классе мы обновляем сведения об адресе указанного поставщика, сначала считывая запись одного поставщика в , SuppliersDataTable а затем задаем Addressзначения столбца , Cityи 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 существующих значений . В случае, когда адрес, город и страна или регион совпадают с существующими данными, изменения не будут вноситься, и SupplierRowRowState они будут помечены как без изменений. В результате при вызове метода DAL Update вызов базы данных не выполняется, так как SuppliersRow не был изменен.

Чтобы принять это изменение, замените операторы, которые слепо присваивают переданные значения address, city, country/region, следующим кодом:

' 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. Далее мы добавили кнопки Обновить все над и под DataList. После внесения пользователем изменений и нажатия одной из кнопок DataListItem Обновить все перечисляются и выполняется вызов SuppliersBLL метода класса s UpdateSupplierAddress .

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

Об авторе

Скотт Митчелл( 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.