●DataGridに行の削除機能を追加 (ch57DataGrid1.aspx)
ここで作成するサンプルは、DataGridにOracleデータベースのCustomers表をバインドして表示します
Customers表から行(レコード)を抽出するには、パッケージ(CustomerPackage)に登録されているストアドプロシージャ(GetCustomersGT40)を使用します。Customers表から行を削除するには、ストアドプロシージャ(DeleteCustomers)を使用します。
iSQL*PlusまたはSQL*Plusを起動して、事前にパッケージ仕様部(C:\vbora\sql\CustomerPackage.sql)とパッケージ本体部(C:\vbora\sql\CustomerPackageBody.sql)を作成してください。
パッケージ仕様部(CustomerPackage.sql)
CREATE OR REPLACE PACKAGE
TYPE rcurCustomers IS REF CURSOR;
PROCEDURE GetCustomersGT40(
orcurCustomers OUT rcurCustomers);
PROCEDURE DeleteCustomers(
iCustomerID IN NUMBER);
END CustomerPackage;
パッケージ本体部(CustomerPackageBody.sql)
CREATE OR REPLACE PACKAGE BODY
PROCEDURE GetCustomersGT40(
orcurCustomers OUT rcurCustomers) IS
BEGIN
OPEN orcurCustomers FOR
SELECT *
FROM Customers
WHERE CustomerID > 40
ORDER BY CustomerID;
END GetCustomersGT40;
PROCEDURE DeleteCustomers(
iCustomerID IN NUMBER) IS
BEGIN
DELETE
FROM Customers
WHERE CustomerID = iCustomerID;
END DeleteCustomers;
END CustomerPackage;
このサンプルでは、以下のノウハウを習得することができます。
▼DataGridに行(レコード)を削除する機能を追加する方法
▼DataGridに削除ボタン列を追加する方法
▼削除ボタンクリック時確認メッセージを表示する方法
▼DataGridのDeleteCommandイベントの使い方
▼ストアドプロシージャから削除してレコード件数を取得する方法
▼削除用のストアドプロシージャに楽観的ロックを組み込む方法
▼暗黙カーソル(SQL%ROWCOUNT)の使い方
1. Webフォーム追加
ソリューションエクスプローラからフォルダ[ch5]を右クリックして、新規Webフォーム「ch57DataGrid1」を追加します。
2.
DataGridを作成して編集機能追加
DataGridに編集機能を追加します。

図 DataGridに編集機能追加
3. 削除ボタン列作成
DataGrid1の右クリックから[プロパティビルダ]を選択します。「DataGrid1プロパティ」が表示されたら、左側の[列]を選択します。「使用可能な列」から[ボタン列]をクリックして展開します。[削除]を選択したら
をクリックします。「選択された列」に削除ボタン列が表示されます。ボタン列(ButtonColumn)プロパティの「ボタンの種類」から[PushButton]を選択します。

図 プロパティビルダの[列]から削除ボタン列作成
4. 削除ボタンを中央揃え
「プロパティビルダ」の左側から[書式]を選択します。画面中央の「オブジェクト」から[列]をクリックして展開します。[

図 プロパティビルダの[書式]からさ削除ボタンを中央揃えに設定
5.
DeleteCommandイベント作成
メニューバーから[表示]→[コード]を選択してコードビューに切り替えます。コードビュー左上の「クラス名」のドロップダウンリストから[DataGrid1]を選択します。右上の「メソッド名」のドロップダウンリストから[DeleteCommand]を選択します。DataGrid1_DeleteCommandイベントが作成されたら、以下のコードを追加します。
Private Sub DataGrid1_DeleteCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Handles DataGrid1.DeleteCommand
Dim intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)
DeleteRecord(intCustomerID)
BindGrid()
End Sub
DataGrid1_DeleteCommandイベントの後に、Function DeleteRecordを追加します。
Private Function DeleteRecord(ByVal intCustomerID As Integer) As String
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim cmd As New OracleCommand("CustomerPackage.DeleteCustomers", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.BindByName = True
cmd.Parameters.Add("iCustomerID", OracleDbType.Int32).Value = intCustomerID
con.Open()
Dim intRetValue As Integer = cmd.ExecuteNonQuery()
con.Close()
Return intRetValue
End Function
6.
ItemDataBoundイベント作成
コードビュー左上の「クラス名」のドロップダウンリストから[DataGrid1]を選択します。右上の「メソッド名」のドロップダウンリストから[ItemDataBound]を選択します。DataGrid1_ItemDataBoundイベントが作成されたら、以下のコードを追加します。
Private Sub DataGrid1_ItemDataBound(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs)
Handles DataGrid1.ItemDataBound
If e.Item.ItemType = ListItemType.Item OrElse _
e.Item.ItemType = ListItemType.AlternatingItem Then
Dim btn As Button = CType(e.Item.Cells(5).Controls(0), Button)
btn.Attributes.Add("onclick", "return confirm('削除してよろしいですか?')")
End If
End Sub
7. ブラウザに表示
ソリューションエクスプローラから[ch57DataGrid1.aspx]を右クリックしてブラウザに表示します。DataGridにCustomers表が表示されます。DataGridの右端から[削除]をクリックすると「削除してよろしいですか?」の確認メッセージが表示されます。削除するときは[OK]、中止するときは[キャンセル]をクリックします。

図 DataGridから[削除]をクリックした例
■解説
DataGridに削除機能を組み込むには、「プロパティビルダ」の[列]から[削除]を追加します。削除ボタン列のプロパティ「テキスト」には、ボタンの表題を入力します。デフォルトで「削除」が表示されます。「コマンド名」には、削除を意味する「Delete」を入力します。「ボタンの種類」からは、[LinkButton]または[PushButton]のいずれかを選択します。デフォルトは、[LinkButton]になります。「プロパティビルダ」から[OK]をクリックすると、削除ボタン列が生成されます。
<asp:DataGrid id="DataGrid1" runat="server"
AutoGenerateColumns="False">
<Columns>
<asp:BoundColumn DataField="CustomerID"
ReadOnly="True" HeaderText="ID">
</asp:BoundColumn>
<asp:BoundColumn DataField="CompanyName"
HeaderText="得意先">
</asp:BoundColumn>
<asp:BoundColumn DataField="ContactName"
HeaderText="担当">
</asp:BoundColumn>
<asp:BoundColumn DataField="Phone"
HeaderText="電話">
</asp:BoundColumn>
・・・
<asp:ButtonColumn Text="削除"
ButtonType="PushButton" CommandName="Delete">
</asp:ButtonColumn>
</Columns>
</asp:DataGrid>
DataGridから[削除]をクリックするとWebページがポストバックされて、Page_Load→DataGrid1_DeleteCommandの順にイベントが発生します。
Page_Loadイベントでは、IsPostBackプロパティを調べて初期ロードのときBindGridメソッドを実行します。
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
If Not IsPostBack Then
BindGrid()
End If
End Sub
BindGridメソッドは、CreateDataSetメソッドを実行してCustomers表のDataSetを作成します。CreateDataSetメソッドの引数には、パッケージ(CustomerPackage)のストアドプロシージャ(GetCustomersGT40[1])を指定します。DataGridのDataSourceプロパティにDataSetのオブジェクトを設定して、DataBindメソッドを実行すると、DataGridにDataSetがバインドされてCustomers表が表示されます。
Private Sub BindGrid()
With DataGrid1
.DataSource = CreateDataSet("CustomerPackage.GetCustomersGT40")
.DataKeyField = "CustomerID"
.DataBind()
End With
End Sub
DataGrid1_DeleteCommandイベントでは、DataGridCommandEventArgsオブジェクトのItem.ItemIndexプロパティからカレントのアイテム番号を取得します。DataGridのDataKeysコレクションからカレント行の主キー(CustomerID)を取得して変数に保存します。
Private Sub DataGrid1_DeleteCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)
Handles DataGrid1.DeleteCommand
Dim intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)
DeleteRecord(intCustomerID)
BindGrid()
End Sub
DeleteRecordメソッドは、パッケージ(CustomerPackage)のストアドプロシージャ(DeleteCustomers)を使用してCustomers表から行を削除します。OracleConnectionとOracleCommandのインスタンスを生成したら、OracleCommandオブジェクトのCommandTypeプロパティにCommandType.StoredProcedureを設定します。さらに、BindByNameプロパティにTrueを設定して名前指定のパラメータを使用することを指示します。
PROCEDURE DeleteCustomers(
iCustomerID IN NUMBER) IS
BEGIN
DELETE
FROM Customers
WHERE CustomerID = iCustomerID;
END DeleteCustomers;
cmd.Parameters.Add("iCustomerID", OracleDbType.Int32).Value = intCustomerID
OracleConnectionオブジェクトのOpenメソッドでOracleデータベースを開いたら、OracleCommandオブジェクトのExecuteNonQueryメソッドでストアドプロシージャのDELETE文を実行します。次に、OracleConnectionオブジェクトのCloseメソッドでOracleデータベースを閉じて戻ります。このメソッドからは、戻り値として削除した行数(レコード数[2])を返します。
Private Function DeleteRecord(ByVal intCustomerID As Integer) As String
Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))
Dim cmd As New OracleCommand("CustomerPackage.DeleteCustomers", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.BindByName = True
cmd.Parameters.Add("iCustomerID", OracleDbType.Int32).Value = intCustomerID
con.Open()
Dim intRetValue As Integer = cmd.ExecuteNonQuery()
con.Close()
Return intRetValue
End Function
STEP UP
|
楽観的ロックを組み込む
(ch57DataGrid1a.aspx) ch57DataGrid1.aspxのサンプルは、排他制御を一切考慮していませんので、他のユーザーが更新したデータを削除する可能性があります。ここで紹介するサンプルは、楽観的ロックを採用してすでに他のユーザーがレコードを変更しているときは、排他制御エラーにして再試行させるようにします。以下に、ch57DataGrid1.aspxのサンプルに楽観的ロックを組み込む手順を解説します。 1. ストアドプロシージャの追加 パッケージの仕様部(CustomerPackage)と本体部(CustomerPackageBody)に、ストアドプロシージャ(DeleteCustomersConcurrencyIDRc)を追加します。このストアドプロシージャは、得意先ID(CustomerID)と更新回数(ConcurrencyID)が一致したときに行(レコード)を削除するように改善しています。また、出力パラメータ(oRowCount)に削除されたレコード数を設定して返します。SQL%ROWCOUNTには、削除されたレコード数が格納されています。これで、レコードが他のユーザーから変更されていないときのみ削除されます。 パッケージの仕様部 CREATE OR REPLACE PACKAGE
PROCEDURE DeleteCustomersConcurrencyIDRc( iCustomerID IN NUMBER, iConcurrencyID IN NUMBER, oRowCount OUT NUMBER); END CustomerPackage; パッケージの本体部 CREATE OR REPLACE PACKAGE BODY
PROCEDURE DeleteCustomersConcurrencyIDRc( iCustomerID IN NUMBER,
iConcurrencyID IN NUMBER, oRowCount OUT NUMBER) IS
BEGIN DELETE FROM Customers WHERE CustomerID = iCustomerID AND ConcurrencyID = iConcurrencyID; oRowCount := SQL%ROWCOUNT; END
DeleteCustomersConcurrencyIDRc; END CustomerPackage; 2. DataGridに連結列追加 DataGrid1の「プロパティビルダ」を表示したら、[列]から連結列を作成して連結列(BoundColumn)プロパティの「データフィールド」に「ConcurrencyID」を入力します。[読み取り専用]をクリックしてチェックマークを付けます。「可視」をクリックしてチェックを外します。これで、ConcurrencyIDの連結列が不可視になります。ここで追加した「ConcurrencyID」の連結列を上下の矢印キーを使用して「電話」の連結列の次に移動します。 3. DeleteCommandイベントを書き換え コードビューに切り替えたら、DataGrid1_DeleteCommandを以下のように書き換えます。ConcurrencyIDの連結列から更新回数を取得して変数に保存します。DeleteRecordメソッドに引数intConcurrencyIDを追加します。戻り値が「0」のときは、排他制御エラーのメッセージを表示して再試行させます。 Private Sub DataGrid1_DeleteCommand(ByVal source As
Object,
Dim intConcurrencyID As Integer =
Int32.Parse(e.Item.Cells(4).Text) Dim
intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex) Dim
intAffectedRecords As Integer = DeleteRecord(intCustomerID, intConcurrencyID) If intAffectedRecords = 0 Then Response.Write("該当行が他のユーザーから更新されています!<br>再試行してください.<br>") End If
BindGrid() End Sub 4. Function DeleteRecordの書き換え Function DeleteRecordを以下のように書き換えます。入力パラメータ(iConcurrencyID)と出力パラメータ(oRowCount)を追加します。ExecuteNonQuery[3]メソッド実行後、出力パラメータから削除されたレコード数を取得します。 Private Function DeleteRecord(ByVal intCustomerID As
Integer, _ ByVal intConcurrencyID As Integer) As String Dim con
As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw")) Dim cmd
As New OracleCommand("CustomerPackage.DeleteCustomersConcurrencyIDRc", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.BindByName = True
cmd.Parameters.Add("iCustomerID", OracleDbType.Int32).Value = intCustomerID
cmd.Parameters.Add("iConcurrencyID", OracleDbType.Int32).Value =
intConcurrencyID
cmd.Parameters.Add("oRowCount", OracleDbType.Int32).Direction =
ParameterDirection.Output
con.Open()
cmd.ExecuteNonQuery() Dim intRetValue As Integer =
Int32.Parse(cmd.Parameters("oRowCount").Value)
con.Close()
Return intRetValue End Function 5. ItemDataBoundイベントを書き換え DataGrid1_ItemDataBoundイベントを以下のように書き換えます。DataGridにConcurrencyIDの連結列を追加したので、削除ボタンのオブジェクトを取得するコードをCType(e.Item.Cells(5).Controls(0), Button)からCType(e.Item.Cells(6).Controls(0), Button)に書き換えます。 Private Sub DataGrid1_ItemDataBound(ByVal sender As
Object,
If
e.Item.ItemType = ListItemType.Item OrElse _ e.Item.ItemType =
ListItemType.AlternatingItem Then Dim btn As Button = CType(e.Item.Cells(6).Controls(0),
Button)
btn.Attributes.Add("onclick", "return confirm('削除してよろしいですか?')") End If End Sub |