バッチ更新を実行する (VB)

作成者: Scott Mitchell

PDF のダウンロード

すべての項目が編集モードであり、ページで [すべて更新] ボタンをクリックすることでその値を保存することができる、完全な編集が可能な DataList を作成する方法について説明します。

はじめに

前のチュートリアル では、項目レベルの DataList を作成する方法について説明しました。 標準的な編集が可能な GridView と同様に、DataList の各項目には [編集] ボタンが含まれており、クリックすると項目が編集可能になります。 この項目レベルの編集は、たまにしか更新されないデータに適していますが、特定のユース ケースのシナリオでは、ユーザーが多くのレコードを編集する必要があります。 ユーザーが何十ものレコードを編集する必要があり、強制的に [編集] をクリックして変更を加え、そのたびに [更新] をクリックする必要がある場合、クリック数によって生産性が低下する可能性があります。 このような状況では、すべての項目が編集モードであり、ページの [すべて更新] ボタンをクリックして値を編集できる、完全な編集が可能な DataList を提供することをお勧めします。 (図 1 参照)。

完全に編集可能なデータリストの各項目は変更可能です

図 1: 完全な編集が可能な DataList 内の各項目を変更可能 (クリックするとフルサイズの画像が表示されます)

このチュートリアルでは、ユーザーが完全な編集が可能な DataList を使用してサプライヤーの住所情報を更新できるようにする方法について説明します。

手順 1: DataList の ItemTemplate で編集可能なユーザー インターフェイスを作成する

前のチュートリアルでは、項目レベルの編集可能な標準の DataList を作成するために、次の 2 つのテンプレートを使用しました。

  • ItemTemplate には、読み取り専用のユーザー インターフェイス (各製品の名前と価格を表示するための Label Web コントロール) が含まれていました。
  • EditItemTemplate には、編集モードのユーザー インターフェイス (2 つの TextBox Web コントロール) が含まれていました。

DataList の EditItemIndex プロパティは、EditItemTemplateを使用して (存在する場合)、レンダリングされる DataListItem を指定します。 特に、ItemIndex の値が DataList の EditItemIndex プロパティと一致する DataListItem は、EditItemTemplate を使用してレンダリングされます。 このモデルは、一度に 1 つの項目しか編集できない場合にはうまく機能しますが、完全な編集が可能な DataList を作成する場合にはうまくいきません。

完全に編集可能な DataList の場合は、編集可能なインターフェイスを使用してレンダリングするために、すべてDataListItem が必要です。 これを実現する最も簡単な方法は、ItemTemplate で編集可能なインターフェイスを定義することです。 サプライヤーの住所情報を変更する場合、編集可能なインターフェイスには、テキストとしてサプライヤー名が含まれ、住所、市区町村、国/地域の値のためのテキストボックスが含まれます。

まず BatchUpdate.aspx ページを開き、DataList コントロールを追加し、その ID プロパティを Suppliers に設定します。 DataListのスマートタグから、SuppliersDataSource という名前の新しい ObjectDataSource コントロールを追加します。

SuppliersDataSource という名前の新しい ObjectDataSource を作成する

図 2: SuppliersDataSource という名前の 新しい ObjectDataSource の作成 (クリックするとフルサイズの画像が表示されます)

SuppliersBLL クラスの GetSuppliers() メソッドを使用してデータを取得するように ObjectDataSource を構成します (図 3 参照)。 前のチュートリアルと同様に、ObjectDataSource を使用してサプライヤー情報を更新するのではなく、ビジネス ロジック層を直接操作します。 そのため、[更新] タブでドロップダウン リストを (なし) に設定します (図 4 参照)。

GetSuppliers() メソッドを使用してサプライヤー情報を取得する

図 3: GetSuppliers() メソッドを使用したサプライヤー情報の取得 (クリックするとフルサイズの画像が表示されます)

更新タブのドロップダウンリストを(なし)に設定します

図 4: [更新] タブでドロップダウン リストを (なし) に設定 (クリックするとフルサイズの画像が表示されます)

ウィザードが完了すると、Visual Studio によって DataList の ItemTemplate が自動的に生成され、データ ソースによって返された各データ フィールドが Label Web コントロールに表示されます。 代わりに編集インターフェイスが提供されるように、このテンプレートを変更する必要があります。 ItemTemplate は、DataList のスマート タグから [テンプレートの編集] オプションを使用するか、宣言構文を使用して直接 Designer でカスタマイズできます。

サプライヤーの名前をテキストとして表示し、サプライヤーの住所、市区町村、国/地域の値の TextBox を含む編集インターフェイスを作成します。 これらの変更を行うと、ページの宣言構文は次のようになります。

<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>

Note

前のチュートリアルと同様に、このチュートリアルの DataList ではビュー状態を有効にする必要があります。

ItemTemplateでは、SupplierPropertyLabelSupplierPropertyValue という 2 つの新しい CSS クラスを使用しています。これらは Styles.css クラスに追加され、ProductPropertyLabel および ProductPropertyValue CSS クラスと同じスタイル設定を使用するように構成されています。

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

これらの変更を行った後、ブラウザー経由でこのページにアクセスします。 図 5 に示すように、各 DataList 項目は、サプライヤー名をテキストとして表示し、TextBox を使用して住所、市区町村、国/地域を表示します。

データリスト内の各サプライヤーは編集可能です

図 5: 編集可能な DataList の各サプライヤー (クリックするとフルサイズの画像が表示されます)

手順 2: [すべて更新] ボタンの追加

図 5 の各サプライヤーには、住所、市区町村、国/地域の各フィールドがテキスト ボックスに表示されていますが、現時点では [更新] ボタンは使用できません。 完全な編集が可能な DataList では、項目ごとに更新ボタンがあるのではなく、ページ上に [すべて更新] ボタンが 1 つあり、それをクリックすると DataList 内のすべてのレコードが更新されます。 このチュートリアルでは、ページの上部と下部に、2 つの [すべて更新] ボタンを追加してみましょう (ただし、どちらのボタンをクリックしても同じ効果があります)。

まず、Button Web コントロールを DataList の上に追加し、その ID プロパティを UpdateAll1 に設定します。 次に、2 番目の Button Web コントロールを DataList の下に追加し、その IDUpdateAll2 に設定します。 2 つのボタンの Text プロパティを [すべて更新] に設定します。 最後に、両方の Button Click イベントのイベント ハンドラーを作成します。 各イベント ハンドラーで更新ロジックを重複させるのではなく、そのロジックを 3 番目のメソッド UpdateAllSupplierAddresses にリファクタリングして、イベント ハンドラーが単にこの 3 番目のメソッドを呼び出すようにしましょう。

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 は、[すべて更新] ボタンが追加された後のページを示しています。

ページに「すべて更新」ボタンが 2 つ追加されました

図 6: ページに追加された 2 つの [すべての更新] ボタン (クリックするとフルサイズの画像が表示されます)

手順 3: すべてのサプライヤーの住所情報の更新

DataList のすべての項目で編集インターフェイスを表示し、[すべて更新] ボタンが追加されたので、あとは一括更新を実行するコードを記述するだけです。 具体的には、DataList の項目をループして SuppliersBLL クラスの UpdateSupplierAddress メソッドを呼び出す必要があります。

DataList を構成する DataListItem インスタンスのコレクションは、DataList のItems プロパティを介してアクセスできます。 DataListItem への参照がある場合は、次のコードに示すように、DataKeys コレクションから対応する SupplierID を取得し、次のコードの示すように、ItemTemplate 内の TextBox Web コントロールをプログラムで参照できます。

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 メソッドは Suppliers DataList 内の各 DataListItem ボタンを反復処理し、SuppliersBLL クラスの UpdateSupplierAddress メソッドを呼び出して、対応する値を渡します。 住所、市区町村、または国/地域に渡す値が入力されていない値は、(空白文字列ではなく) Nothing への UpdateSupplierAddress の値であり、基になるレコードのフィールドのデータベース NULL になります。

Note

機能強化として、バッチ更新の実行後に何らかの確認メッセージが表示される状態 Label Web コントロールをページに追加する必要がある場合があります。

変更されたアドレスのみの更新

このチュートリアルで使用するバッチ更新アルゴリズムは、住所情報が変更されたかどうかに関係なく、DataList 内のすべてのサプライヤーに対して UpdateSupplierAddress メソッドを呼び出します。 通常、このようなブラインド更新はパフォーマンスの問題にはなりませんが、データベース テーブルの変更を監査している場合、余計なレコードが増えてしまう可能性があります。 たとえば、トリガーを使用してすべての UPDATESuppliers テーブルを監査テーブルに記録する場合、ユーザーが [すべて更新] ボタンをクリックするたびに、ユーザーが変更を行ったかどうかに関係なく、システム内の各サプライヤーに対して新しい監査レコードが作成されます。

ADO.NET DataTable クラスと DataAdapter クラスは、変更、削除、新しいレコードのみがデータベース通信を行うバッチ更新をサポートするように設計されています。 DataTable の各行にはRowState プロパティがあり、その行が DataTable に追加されたのか、DataTable から削除されたのか、変更されたのか、あるいは変更されていないのかを示します。 DataTable が最初に入力される場合、すべての行は変更なしとマークされます。 行のいずれかの列の値を変更すると、その行が変更されたとマークされます。

SuppliersBLL クラスでは、まず SuppliersDataTable に 1 つのサプライヤー レコードを読み込んで指定されたサプライヤーの住所情報を更新し、次のコードを使用する AddressCityCountry 列の値を設定します。

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

このコードは、渡された住所、市区町村、国/地域の値を、値が変更されたかどうかに関係なく、SuppliersDataTableSuppliersRow に単純に割り当てます。 これらの変更により、SuppliersRowRowState プロパティは変更済みとしてマークされます。 データ アクセス層の Update メソッドが呼び出されると、SupplierRow が変更されたことが確認され、UPDATE コマンドがデータベースに送信されます。

ただし、渡された住所、市区町村、国/地域の値が SuppliersRow の既存の値と異なる場合にのみ割り当てるコードをこのメソッドに追加したとします。 住所、市区町村、国/地域が既存のデータと同じである場合、変更は行われず、SupplierRowRowState は変更なしとしてマークされたままになります。 結果として、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 メソッドの呼び出しをバイパスすることもできます。 DB ダイレクト メソッドは、データベース呼び出しが実際に必要かどうかを判断するために RowState を確認できる SuppliersRow インスタンスが渡されないため、この方法は、DB ダイレクト メソッドを使用している場合に適しています。

Note

UpdateSupplierAddress メソッドが呼び出されるたびに、更新されたレコードに関する情報を取得するためにデータベースへの呼び出しが行われます。 その後、データに変更がある場合は、テーブル行を更新するためにデータベースへの別の呼び出しが行われます。 このワークフローは、BatchUpdate.aspx ページからのすべての変更を含む EmployeesDataTable インスタンスを受け入れる UpdateSupplierAddress メソッド オーバーロードを作成することによって最適化できます。 その後、データベースへの呼び出しを 1 回行い、Suppliers テーブルからすべてのレコードを取得できます。 その後、2 つの結果セットを列挙し、変更が発生したレコードのみを更新できます。

まとめ

このチュートリアルでは、完全な編集が可能な DataList を作成し、ユーザーが複数のサプライヤーの住所情報をすばやく変更できるようにする方法について説明しました。 まず、DataList の ItemTemplate にあるサプライヤーの住所、市区町村、国/地域の値の TextBox Web コントロールの編集インターフェイスで定義しました。 次に、DataList の上下に [すべて更新] ボタンを追加しました。 ユーザーが変更を行い、[すべて更新] ボタンのいずれかをクリックすると、DataListItem が列挙され、SuppliersBLL クラスの UpdateSupplierAddress メソッドの呼び出しが行われます。

プログラミングに満足!

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジに取り組んでいます。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズは24時間で2.0 ASP.NET 自分自身を教えています。 にアクセスするか、ブログを使用して にアクセスmitchell@4GuysFromRolla.comできます。これは でhttp://ScottOnWriting.NET見つけることができます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、Zack Jones と Ken Pespisa でした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、 にmitchell@4GuysFromRolla.com行をドロップしてください。