Выполнение пакетных обновлений (VB)
Узнайте, как создать полностью редактируемый список данных, где все его элементы находятся в режиме редактирования и значения которых можно сохранить, нажав кнопку "Обновить все" на странице.
Введение
В предыдущем руководстве мы рассмотрели, как создать 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
.
Рис. 2. Создание объекта ObjectDataSource С именем (SuppliersDataSource
щелкните, чтобы просмотреть изображение полного размера)
Настройте ObjectDataSource для получения данных с помощью SuppliersBLL
метода класса GetSuppliers()
(см. рис. 3). Как и в предыдущем руководстве, а не обновите сведения о поставщике с помощью ObjectDataSource, мы будем работать непосредственно с уровнем бизнес-логики. Поэтому в раскрывающемся списке (Нет) на вкладке UPDATE (см. рис. 4).
Рис. 3. Получение сведений о поставщике GetSuppliers()
с помощью метода (щелкните, чтобы просмотреть изображение полного размера)
Рис. 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 для отображения адреса, города и страны или региона.
Рис. 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
, а затем задали 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
. В случае, если адрес, город и страна или регион совпадают с существующими данными, изменения не будут вноситься, и они 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.