バッチ更新を実行する (C#)
すべてのアイテムが編集モードで、ページの [すべて更新] ボタンをクリックして値を保存できる、完全に編集可能な DataList を作成する方法について説明します。
はじめに
前の チュートリアル では、項目レベルの DataList を作成する方法を調べました。 標準の編集可能な GridView と同様に、DataList の各項目には[編集]ボタンが含まれており、クリックするとアイテムが編集可能になります。 この項目レベルの編集は、時折更新されるデータに対しては適切に機能しますが、特定のユース ケースシナリオでは、ユーザーが多くのレコードを編集する必要があります。 ユーザーが何十ものレコードを編集する必要があり、強制的に [編集] をクリックして変更を加え、それぞれに対して [更新] をクリックすると、クリックの量が生産性を低下させる可能性があります。 このような状況では、完全に編集可能な DataList を提供することをお勧めします。この DataList では、 すべての アイテムが編集モードで、ページの [すべて更新] ボタンをクリックして値を編集できます (図 1 を参照)。
図 1: 完全に編集可能な DataList 内の各項目を変更できます (フルサイズの画像を表示する場合はクリックします)
このチュートリアルでは、ユーザーが完全に編集可能な DataList を使用してサプライヤーの住所情報を更新できるようにする方法について説明します。
手順 1: DataList の ItemTemplate で編集可能なユーザー インターフェイスを作成する
前のチュートリアルでは、項目レベルの編集可能な標準の DataList を作成し、次の 2 つのテンプレートを使用しました。
ItemTemplate
には、読み取り専用ユーザー インターフェイス (各製品の名前と価格を表示するためのラベル Web コントロール) が含まれていました。EditItemTemplate
には、編集モードのユーザー インターフェイス (2 つの TextBox Web コントロール) が含まれていました。
DataList の EditItemIndex
プロパティは、 を使用してレンダリングされる内容 DataListItem
(存在する場合) を指定します EditItemTemplate
。 特に、DataListItem
DataList の EditItemIndex
プロパティと一致する値を持ItemIndex
つ は、 をEditItemTemplate
使用してレンダリングされます。 このモデルは、一度に 1 つの項目しか編集できないが、完全に編集可能な DataList を作成するときに分解される場合に適切に機能します。
完全に編集可能な DataList の場合は、編集可能なインターフェイスをDataListItem
使用して、すべての がレンダリングされるようにします。 これを実現する最も簡単な方法は、 で編集可能なインターフェイスを ItemTemplate
定義することです。 仕入先住所情報を変更する場合、編集可能なインターフェイスには、サプライヤー名がテキストとして、住所、市区町村、国/地域の値の TextBox が含まれます。
まず、ページを BatchUpdate.aspx
開き、DataList コントロールを追加し、そのプロパティを ID
に Suppliers
設定します。 DataList のスマート タグから、 という名前 SuppliersDataSource
の新しい ObjectDataSource コントロールを追加することを選択します。
図 2: 名前付きの SuppliersDataSource
新しい ObjectDataSource を作成する (フルサイズの画像を表示する場合はクリックします)
クラス s GetSuppliers()
メソッドを使用してデータを取得するように ObjectDataSource をSuppliersBLL
構成します (図 3 を参照)。 前のチュートリアルと同様に、ObjectDataSource を使用してサプライヤー情報を更新するのではなく、ビジネス ロジック レイヤーを直接操作します。 そのため、[更新] タブでドロップダウン リストを (なし) に設定します (図 4 を参照)。
図 3: メソッドを使用して仕入先情報を取得する GetSuppliers()
(クリックするとフルサイズの画像が表示されます)
図 4: [更新] タブで [Drop-Down リスト] を [(なし)] に設定します (フルサイズの画像を表示する 場合はクリックします)
ウィザードが完了すると、Visual Studio によって DataList が ItemTemplate
自動的に生成され、データ ソースによって返された各データ フィールドがラベル 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>
注意
前のチュートリアルと同様に、このチュートリアルの DataList では、ビューステートを有効にする必要があります。
では、ItemTemplate
SupplierPropertyLabel
2 つの新しい CSS クラス と SupplierPropertyValue
を使用します。これは、 クラスにStyles.css
追加され、 クラスと ProductPropertyValue
CSS クラスと同じスタイル設定をProductPropertyLabel
使用するように構成されています。
.ProductPropertyLabel, .SupplierPropertyLabel
{
font-weight: bold;
text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
padding-right: 35px;
}
これらの変更を行った後、ブラウザーからこのページにアクセスします。 図 5 に示すように、各 DataList 項目にはサプライヤー名がテキストとして表示され、TextBoxes を使用して住所、市区町村、国/地域が表示されます。
図 5: DataList 内の各サプライヤーは編集可能です (フルサイズの画像を表示する場合はクリックします)
手順 2: [すべて更新] ボタンを追加する
図 5 の各サプライヤーには、住所、市区町村、国/地域のフィールドが TextBox に表示されていますが、現在、[更新] ボタンはありません。 アイテムごとに [更新] ボタンを使用するのではなく、完全に編集可能な DataList を使用すると、通常、ページ上に 1 つの [すべて更新] ボタンがあり、クリックすると DataList 内のすべての レコードが更新されます。 このチュートリアルでは、2 つの [すべて更新] ボタン (ページの上部に 1 つ、下部に 1 つ) を追加します (ただし、いずれかのボタンをクリックすると同じ効果が得られます)。
まず、DataList の上に Button Web コントロールを追加し、そのプロパティを ID
に UpdateAll1
設定します。 次に、DataList の下に 2 つ目の Button Web コントロールを追加し、 を ID
に設定します UpdateAll2
。 2 つのボタンの Text
プロパティを [すべて更新] に設定します。 最後に、両方の Buttons イベントのイベント ハンドラーを Click
作成します。 各イベント ハンドラーで更新ロジックを複製するのではなく、そのロジックを 3 番目のメソッド () にリファクタリングし、 UpdateAllSupplierAddresses
イベント ハンドラーがこの 3 番目のメソッドを呼び出すだけです。
protected void UpdateAll1_Click(object sender, EventArgs e)
{
UpdateAllSupplierAddresses();
}
protected void UpdateAll2_Click(object sender, EventArgs e)
{
UpdateAllSupplierAddresses();
}
private void UpdateAllSupplierAddresses()
{
// TODO: Write code to update _all_ of the supplier addresses in the DataList
}
図 6 は、[すべて更新] ボタンが追加された後のページを示しています。
図 6: 2 つの [すべての更新] ボタンがページに追加されました (クリックするとフルサイズの画像が表示されます)
手順 3: すべての仕入先住所情報を更新する
編集インターフェイスが表示され、[すべて更新] ボタンが追加された DataList のすべての項目で、残っているのはバッチ更新を実行するコードを記述することです。 具体的には、DataList の項目をループ処理し、それぞれに対してクラス s UpdateSupplierAddress
メソッドをSuppliersBLL
呼び出す必要があります。
DataList を構成するインスタンスの DataListItem
コレクションには、DataList の Items
プロパティを使用してアクセスできます。 へのDataListItem
参照を使用すると、次のコードに示すように、 コレクションからDataKeys
対応する SupplierID
を取得し、 内ItemTemplate
の TextBox Web コントロールをプログラムで参照できます。
private void UpdateAllSupplierAddresses()
{
// Create an instance of the SuppliersBLL class
SuppliersBLL suppliersAPI = new SuppliersBLL();
// Iterate through the DataList's items
foreach (DataListItem item in Suppliers.Items)
{
// Get the supplierID from the DataKeys collection
int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
// Read in the user-entered values
TextBox address = (TextBox)item.FindControl("Address");
TextBox city = (TextBox)item.FindControl("City");
TextBox country = (TextBox)item.FindControl("Country");
string addressValue = null, cityValue = null, countryValue = null;
if (address.Text.Trim().Length > 0)
addressValue = address.Text.Trim();
if (city.Text.Trim().Length > 0)
cityValue = city.Text.Trim();
if (country.Text.Trim().Length > 0)
countryValue = country.Text.Trim();
// Call the SuppliersBLL class's UpdateSupplierAddress method
suppliersAPI.UpdateSupplierAddress
(supplierID, addressValue, cityValue, countryValue);
}
}
ユーザーが [すべて更新] ボタンのいずれかをクリックすると、メソッドは UpdateAllSupplierAddresses
DataList 内の各DataListItem
ボタンをSuppliers
反復処理し、クラスの メソッドUpdateSupplierAddress
をSuppliersBLL
呼び出して、対応する値を渡します。 住所、市区町村、または国/地域のパスに入力されていない値は、(空白の Nothing
文字列ではなく) の UpdateSupplierAddress
値であり、基になるレコードのフィールドのデータベース NULL
になります。
注意
機能強化として、バッチ更新の実行後に確認メッセージが表示される状態ラベル Web コントロールをページに追加できます。
変更されたアドレスのみを更新する
このチュートリアルで使用するバッチ更新アルゴリズムは、住所情報が UpdateSupplierAddress
変更されているかどうかに関係なく、DataList 内のすべての サプライヤーに対して メソッドを呼び出します。 このようなブラインド更新は通常、パフォーマンスの問題ではありませんが、データベース テーブルの変更を監査すると、余分なレコードが発生する可能性があります。 たとえば、トリガーを使用してテーブルのすべての UPDATE
を監査テーブルに Suppliers
記録する場合、ユーザーが [すべて更新] ボタンをクリックするたびに、ユーザーが変更を加えたかどうかに関係なく、システム内のサプライヤーごとに新しい監査レコードが作成されます。
ADO.NET DataTable クラスと DataAdapter クラスは、変更、削除、および新しいレコードのみがデータベース通信の結果となるバッチ更新をサポートするように設計されています。 DataTable の各行には RowState
、 行が DataTable に追加されたか、その行から削除されたか、変更されたか、変更されていないかを示すプロパティがあります。 DataTable が最初に設定されると、すべての行が変更されずにマークされます。 行の列の値を変更すると、行が変更済みとしてマークされます。
クラスでは、SuppliersBLL
最初に 1 つの仕入先レコードを に読み取り、次にSuppliersDataTable
、次のコードを使用して 、City
、および Country
列の値をAddress
設定することで、指定した仕入先の住所情報を更新します。
public bool UpdateSupplierAddress
(int supplierID, string address, string city, string country)
{
Northwind.SuppliersDataTable suppliers =
Adapter.GetSupplierBySupplierID(supplierID);
if (suppliers.Count == 0)
// no matching record found, return false
return false;
else
{
Northwind.SuppliersRow supplier = suppliers[0];
if (address == null)
supplier.SetAddressNull();
else
supplier.Address = address;
if (city == null)
supplier.SetCityNull();
else
supplier.City = city;
if (country == null)
supplier.SetCountryNull();
else
supplier.Country = country;
// Update the supplier Address-related information
int rowsAffected = Adapter.Update(supplier);
// Return true if precisely one row was updated,
// otherwise false
return rowsAffected == 1;
}
}
このコードでは、値が変更されたかどうかに関係なく、渡された住所、市区町村、国/地域 SuppliersRow
の値を の に SuppliersDataTable
単純に割り当てます。 これらの変更により、 プロパティがSuppliersRow
RowState
変更済みとしてマークされます。 データ アクセス層の Update
メソッドが呼び出されると、 が変更されたことが確認 SupplierRow
され、コマンドがデータベースに送信 UPDATE
されます。
ただし、渡された住所、市区町村、国/地域の値が既存の値と異なる場合にのみ割り当てるために、このメソッドにコードを SuppliersRow
追加したとします。 住所、市区町村、国/地域が既存のデータと同じである場合、変更は行SupplierRow
RowState
われず、s は変更されていないものとしてマークされます。 結果として、DAL の Update
メソッドが呼び出されると、 が変更されていないため SuppliersRow
、データベース呼び出しは行われません。
この変更を適用するには、渡された住所、市区町村、国/地域の値を盲目的に割り当てるステートメントを次のコードに置き換えます。
// Only assign the values to the SupplierRow's column values if they differ
if (address == null && !supplier.IsAddressNull())
supplier.SetAddressNull();
else if ((address != null && supplier.IsAddressNull()) ||
(!supplier.IsAddressNull() &&
string.Compare(supplier.Address, address) != 0))
supplier.Address = address;
if (city == null && !supplier.IsCityNull())
supplier.SetCityNull();
else if ((city != null && supplier.IsCityNull()) ||
(!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0))
supplier.City = city;
if (country == null && !supplier.IsCountryNull())
supplier.SetCountryNull();
else if ((country != null && supplier.IsCountryNull()) ||
(!supplier.IsCountryNull() &&
string.Compare(supplier.Country, country) != 0))
supplier.Country = country;
このコードを追加すると、DAL メソッド Update
は、アドレス関連の値が変更されたレコードに対してのみ、ステートメントをデータベースに送信 UPDATE
します。
または、渡されたアドレス フィールドとデータベース データに違いがあるかどうかを追跡し、存在しない場合は DAL メソッド Update
の呼び出しをバイパスします。 この方法は、DB ダイレクト メソッドを使用している場合に適切に機能します。これは、データベース呼び出しがRowState
実際に必要かどうかを確認できるインスタンスが DB ダイレクト メソッドに渡SuppliersRow
されないためです。
注意
メソッドが UpdateSupplierAddress
呼び出されるたびに、更新されたレコードに関する情報を取得する呼び出しがデータベースに対して行われます。 その後、データに変更がある場合は、テーブル行を更新するためにデータベースの別の呼び出しが行われます。 このワークフローは、ページからBatchUpdate.aspx
のすべての変更を含むインスタンスをUpdateSupplierAddress
EmployeesDataTable
受け入れるメソッド オーバーロードを作成することで最適化できます。 その後、データベースを 1 回呼び出して、テーブルからすべてのレコードを Suppliers
取得できます。 その後、2 つの結果セットを列挙し、変更が発生したレコードのみを更新できます。
まとめ
このチュートリアルでは、完全に編集可能な DataList を作成し、ユーザーが複数のサプライヤーの住所情報をすばやく変更できるようにする方法について説明しました。 まず、DataList ItemTemplate
の の仕入先の住所、市区町村、国/地域の値に対して TextBox Web コントロールを編集インターフェイスとして定義することから始めました。 次に、DataList の上下に [すべて更新] ボタンを追加しました。 ユーザーが自分の変更を行い、[すべて更新] ボタンのいずれかをクリックすると、DataListItem
s が列挙され、クラス s UpdateSupplierAddress
メソッドのSuppliersBLL
呼び出しが行われます。
プログラミングに満足!
著者について
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行をドロップしてください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示