DataGridに行の新規登録機能追加 (ch58DataGrid1.aspx)

 

ここで作成するサンプルは、DataGridOracleデータベースのCustomers表をバインドして表示します。

 

Customers表から行(レコード)を抽出するには、パッケージ(CustomerPackage)に登録されているストアドプロシージャ(GetCustomersGT40)を使用します。Customers表に行を追加するには、ストアドプロシージャ(InsertCustomers)を使用します。

 

iSQL*PlusまたはSQL*Plusを起動して、事前にパッケージ仕様部(C:\vbora\sql\CustomerPackage.sql)とパッケージ本体部(C:\vbora\sql\CustomerPackageBody.sql)を作成してください。

 

パッケージ仕様部(CustomerPackage.sql)

CREATE OR REPLACE PACKAGE CustomerPackage AS

  TYPE rcurCustomers IS REF CURSOR;

  PROCEDURE GetCustomersGT40(

    orcurCustomers OUT rcurCustomers);

  PROCEDURE InsertCustomers(

    iCompanyName IN VARCHAR2,

    iContactName IN VARCHAR2,

    iPhone IN VARCHAR2);

END CustomerPackage;

 

パッケージ本体部(CustomerPackageBody.sql)

CREATE OR REPLACE PACKAGE BODY CustomerPackage AS

  PROCEDURE GetCustomersGT40(

    orcurCustomers OUT rcurCustomers) IS

  BEGIN

    OPEN orcurCustomers FOR

      SELECT *

FROM Customers

      WHERE CustomerID > 40

      ORDER BY CustomerID;

  END GetCustomersGT40;

  PROCEDURE InsertCustomers(

    iCompanyName IN VARCHAR2,

    iContactName IN VARCHAR2,

    iPhone IN VARCHAR2) IS

  BEGIN

    INSERT INTO Customers

      (CompanyName, ContactName, Phone)

      VALUES (iCompanyName, iContactName, iPhone);

  END InsertCustomers;

END CustomerPackage;

 

AccessAutoNumber型、SQL ServerIdentity型の列(フィールド)をOracleで実現するためには、SEQUECETRIGGERを使用します。このサンプルで使用するCustomers表は、以下のようなSEQUENCETRIGGERを使用してCustomerIDAutoNumber/Identity型にしています。

 

Customers表には、すでに50件のレコードがロードされていますので、SEQUENCESTART WITHでは「51」を指定しています。TRIGGERは、Customers表にINSERT文が実行されるとき、CustomerIDCustomers_CustomerID_Seqから生成して自動採番します。Customers_CustomerID_SeqNEXTVALでシーケンス番号を取得するにはDUAL表を使用します。

 

CREATE SEQUENCE Customers_CustomerID_Seq

  NOCYCLE NOORDER NOCACHE NOMAXVALUE MINVALUE 1

  INCREMENT BY 1 START WITH 51;

 

CREATE OR REPLACE TRIGGER Customers_Tri

BEFORE INSERT ON Customers

FOR EACH ROW

BEGIN

  SELECT Customers_CustomerID_Seq.NEXTVAL

  INTO :new.CustomerID

  FROM DUAL;

END;

 

このサンプルで使用するTRIGGERは、INSERT文でCustomerIDを指定しても無効として自動採番します。INSERT文でCustomerIDを有効にするには、TRIGGERを以下のように書き換えます。

 

IF :new.CustomerID IS NULL THEN

  SELECT Customers_CustomerID_Seq.NEXTVAL

  INTO :new.CustomerID

  FROM DUAL;

END IF;

 

このサンプルでは、以下のノウハウを習得することができます。

 

DataGridに新規行(レコード)を追加する機能を組み込む方法

Oracleデータベースの表にオートナンバー型の列を作成する方法

▼表に新規登録して行(レコード)のID(シーケンス)を取得する方法

DataTableAutoIncremenntAutoIncremnetSeedAutoIncrementStepプロパティの使い方

DataTableNewRowメソッドの使い方

DataTableRowsコレクションのAddメソッドの使い方

 

SEQUENCETRIGGERの使い方

SEQUNCECURVALNEXTVALの使い方

FROM DUALの使い方

:new.IDの使い方

 

 

1. Webフォーム追加

 

ソリューションエクスプローラからフォルダ[ch5]を右クリックして、新規Webフォーム「ch58DataGrid1」を追加します。

 

2. DataGridを作成して編集/削除機能追加

 

DataGridに編集機能と削除機能を追加します。

 

fig5-8-1

DataGridに編集と削除ボタン追加

 

3. 新規登録ボタン作成

 

ツールボックスの[Webフォーム]からButtonをドラッグ&ドロップして、DataGrid1の左下にButton1のオブジェクトを作成します。Button1のプロパティウィンドウから「Text」プロパティに「新規登録」を設定します。「ID」のプロパティを「btnAddRow」に書き換えます。

 

4. Clickイベント作成

 

デザイナの新規登録ボタンをダブルクリックして、コードビューに切り替えます。btnAddRow_Clickイベントが作成されたら、次のコードを追加します。

 

Private Sub btnAddRow_Click(ByVal sender As Object, ByVal e As System.EventArgs)

cccHandles btnAddRow.Click

  Dim dr As DataRow = mdt.NewRow

  mdt.Rows.Add(dr)

  Me.AddingNew = True

  Session(mCachekey) = mdt

  DataGrid1.EditItemIndex = DataGrid1.Items.Count

  BindGrid()

End Sub

 

5. AddingNewプロパティ追加

 

モジュールクラスの最後に、AddingNewのプロパティを追加します。

 

Public Property AddingNew() As Boolean

  Get

    Dim obj As Object = ViewState("AddingNew")

    If obj Is Nothing Then

      Return False

    End If

    Return CType(obj, Boolean)

  End Get

 

  Set(ByVal Value As Boolean)

    ViewState("AddingNew") = Value

  End Set

End Property

 

6. Page_Loadイベントの書き換え

 

クラスレベルの変数mdtと定数mCachekeyを追加したら、Page_Loadイベントを以下のように書き換えます。

 

Private mdt As DataTable

Private Const mCachekey = "ch58DataGrid1DataTable"

 

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)

cccHandles MyBase.Load

  If Not IsPostBack Then

    BindGrid()

  Else

    mdt = Session(mCachekey)

  End If

End Sub

 

7. Sub BindGridの書き換え

 

Sub BindGridを以下にように書き換えます。

 

Private Sub BindGrid()

  If mdt Is Nothing Then

    mdt = CreateDataTable("CustomerPackage.GetCustomersGT40")

    Dim dc As DataColumn = mdt.Columns("CustomerID")

    With dc

      .AutoIncrement = True

      .AutoIncrementSeed = -1

      .AutoIncrementStep = -1

    End With

    mdt.PrimaryKey = New DataColumn() {dc}

    Session(mCachekey) = mdt

  End If

  With DataGrid1

    .DataSource = mdt

    .DataKeyField = "CustomerID"

    .DataBind()

  End With

End Sub

 

8. CancelCommandイベントの書き換え

 

DataGrid1_CancelCommandイベントを以下のように書き換えます。

 

Private Sub DataGrid1_CancelCommand(ByVal source As Object,

cccByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)

cccHandles DataGrid1.CancelCommand

  If Me.AddingNew Then

    Dim dr As DataRow = mdt.Rows(mdt.Rows.Count - 1)

    dr.RejectChanges()

    Session(mCachekey) = mdt

  End If

  Me.AddingNew = False

  DataGrid1.EditItemIndex = -1

  BindGrid()

End Sub

 

9. UpdateCommandイベントの書き換え

 

DataGrid1_UpdateCommandイベントを以下にように書き換えます。

 

Private Sub DataGrid1_UpdateCommand(ByVal source As Object, ByVal e As cccSystem.Web.UI.WebControls.DataGridCommandEventArgs) Handles DataGrid1.UpdateCommand

  Dim strCompanyName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text

  Dim strContactName As String = CType(e.Item.Cells(2).Controls(0), TextBox).Text

  Dim strPhone As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text

 

  If Me.AddingNew Then

    InsertRecord(strCompanyName, strContactName, strPhone)

  Else

    Dim intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)

    UpdateRecord(strCompanyName, strContactName, strPhone, intCustomerID)

  End If

 

  Me.AddingNew = False

  DataGrid1.EditItemIndex = -1

  mdt = Nothing

BindGrid()

End Sub

 

10. InsertRecordを追加

 

クラスモジュールの最後に、Function InsertRecordを追加します。

 

Private Function InsertRecord(ByVal strCompanyName As String, _

  ByVal strContactName As String, _

  ByVal strPhone As String) As Integer

 

  Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))

  Dim cmd As New OracleCommand("CustomerPackage.InsertCustomers", con)

 

  With cmd

    .CommandType = CommandType.StoredProcedure

    .BindByName = True

    .Parameters.Add("iCompanyName", OracleDbType.Varchar2, 40).Value = strCompanyName

    .Parameters.Add("iContactName", OracleDbType.Varchar2, 30).Value = strContactName

    .Parameters.Add("iPhone", OracleDbType.Varchar2, 24).Value = strPhone

  End With

 

  con.Open()

  Dim intRetValue As Integer = cmd.ExecuteNonQuery()

  con.Close()

  Return intRetValue

End Function

 

11. ブラウザに表示

 

ソリューションエクスプローラから[ch58DataGrid1.aspx]を右クリックしてブラウザに表示します。DataGridCustomers表が表示されます。Webページから[新規登録]をクリックすると、DataGridに空白行が追加されますので、テキストボックスに得意先、担当、電話を入力して[更新]をクリックします。[中止]をクリックすると、DataGridから空白行が削除されます。空白行のID列には、意図的に負の番号が採番されるようにしています。

 

fig5-8-3

[新規登録]をクリックして空白行追加

 

■解説

 

DataGridに新規行(レコード)を追加するには、ツールボックスからButtonをドラッグ&ドロップしてWebフォームに新規登録ボタンを作成します。

 

<asp:button id="btnAddRow" runat="server"

  Text="新規登録">

</asp:button>

 

デザイナに新規登録ボタンが作成されたら、ボタンをダブルクリックしてClickイベントを作成します。btnAddRow_Clickイベントでは、DataTableオブジェクトのNewRowメソッドを実行してDataRowオブジェクトを作成します。DataTableRowsコレクションのAddメソッドで、DataRowDataTableに追加します。

 

DataTableCustomerID列のAutoIncrementプロパティにTrueが設定されていますので、得意先ID(CustomerID)が自動採番されます。AutoIncrementSeedプロパティに「-1」が設定されていますので負の番号が採番されます。

 

Dim dc As DataColumn = mdt.Columns("CustomerID")

With dc

  .AutoIncrement = True

  .AutoIncrementSeed = -1

  .AutoIncrementStep = -1

End With

 

AddingNewプロパティにTrueを設定して、DataTableをセッションステートに保存します。DataGridEditItemIndexプロパティに、新規に追加したDataRowのインデックス番号を設定して、BindGridメソッドを実行します。DataGridに空白行が編集モードで表示されます。

 

Private Sub btnAddRow_Click(ByVal sender As Object, ByVal e As System.EventArgs)

cccHandles btnAddRow.Click

  Dim dr As DataRow = mdt.NewRow

  mdt.Rows.Add(dr)

  Me.AddingNew = True

  Session(mCachekey) = mdt

  DataGrid1.EditItemIndex = DataGrid1.Items.Count

  BindGrid()

End Sub

 

空白行のテキストボックスに、得意先、担当、電話を入力して[更新]をクリックすると、WebページがポストバックされてPage_LoadDataGrid1_UpdateCommandの順にイベントが発生します。[中止]をクリックしたときは、Page_LoadDataGrid1_CancelCommandの順にイベントが発生します。

 

Page_Loadイベントでは、IsPostBackプロパティを調べて初期ロードまたはポストバックか調べます。初期ロードのときは、BindGridメソッドを実行してDataGridCustomers表をバインドします。ポストバックのときは、セッションステートからDataTableを復元します。

 

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)

cccHandles MyBase.Load

  If Not IsPostBack Then

    BindGrid()

  Else

    mdt = Session(mCachekey)

  End If

End Sub

 

DataGrid1_UpdateCommandイベントでは、DataGridCommandEventArgsオブジェクトのe.Item.CellsコレクションからTextBoxのオブジェクトを取得します。TextBoxTextプロパティから得意先、担当、電話を取得して変数に保存します。AddingNewプロパティを調べて、新規登録ならInsertRecordメソッドを実行します。新規登録でないときは、UpdateRecordメソッドを実行します。

 

レコードを追加、更新したら、AddingNewプロパティにFalseを設定して初期化します。DataGridEditItemIndexプロパティに「-1」を設定して、編集モードを解除します。DataTableオブジェクトの変数をNullに初期化したら、BindGridメソッドを実行してCustomers表をバインドします。変数mdtNullに初期化すると、BindGridCustomers表をOracleのデータベースから読み込み[1]ます。

 

Private Sub DataGrid1_UpdateCommand(ByVal source As Object, ByVal e As cccSystem.Web.UI.WebControls.DataGridCommandEventArgs)

cccHandles DataGrid1.UpdateCommand

  Dim strCompanyName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text

  Dim strContactName As String = CType(e.Item.Cells(2).Controls(0), TextBox).Text

  Dim strPhone As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text

 

  If Me.AddingNew Then

    InsertRecord(strCompanyName, strContactName, strPhone)

  Else

    Dim intCustomerID As Integer = DataGrid1.DataKeys(e.Item.ItemIndex)

    UpdateRecord(strCompanyName, strContactName, strPhone, intCustomerID)

  End If

 

  Me.AddingNew = False

  DataGrid1.EditItemIndex = -1

  mdt = Nothing

BindGrid()

End Sub

 

InsertRecordメソッドは、新規行をCustomers表に追加します。OracleConnectionOracleCommandのインスタンスを生成します。OracleConnectionの引数には、Oracleデータベースの接続文字列を指定します。OracleCommandの引数には、パッケージ(CustomerPackage)に登録されているストアドプロシージャ(InsertCustomers)を指定します。

 

OracleCommandオブジェクトのCommandTypeプロパティにCommandType.StoredProcedureBindByNameプロパティにTrueを設定します。

 

PROCEDURE InsertCustomers(

  iCompanyName IN VARCHAR2,

  iContactName IN VARCHAR2,

  iPhone IN VARCHAR2) IS

BEGIN

  INSERT INTO Customers

    (CompanyName, ContactName, Phone)

    VALUES (iCompanyName, iContactName, iPhone);

END InsertCustomers;

 

ParametersコレクションのAddメソッドには、ストアドプロシージャ(InsertCustomers[2])に宣言しているパラメータ名を指定します。

 

cmd.Parameters.Add("iCompanyName", OracleDbType.Varchar2, 40).Value = strCompanyName

 

OracleConnectionオブジェクトのOpenメソッドでOracleデータベースを開いたら、OracleCommandオブジェクトのExecuteNonQueryメソッドでストアドプロシージャを実行します。OracleConnectionオブジェクトのCloseメソッドでOracleデータベースを閉じたら、ExecuteNonQuery[3]メソッドの戻り値を返します。

 

Private Function InsertRecord(ByVal strCompanyName As String, _

  ByVal strContactName As String, _

  ByVal strPhone As String) As Integer

 

  Dim con As New OracleConnection(ConfigurationSettings.AppSettings("conStringOraNw"))

  Dim cmd As New OracleCommand("CustomerPackage.InsertCustomers", con)

 

  With cmd

    .CommandType = CommandType.StoredProcedure

    .BindByName = True

    .Parameters.Add("iCompanyName", OracleDbType.Varchar2, 40).Value = strCompanyName

    .Parameters.Add("iContactName", OracleDbType.Varchar2, 30).Value = strContactName

    .Parameters.Add("iPhone", OracleDbType.Varchar2, 24).Value = strPhone

  End With

 

  con.Open()

  Dim intRetValue As Integer = cmd.ExecuteNonQuery()

  con.Close()

  Return intRetValue

End Function

 

DataGrid1_CancelCommandイベントでは、空白行が追加されたか調べて元の状態に復元します。AddingNewプロパティにTrueが設定されているときは、DataTableに空白行のDataRowが追加されています。空白行を削除するには、DataTableRowsコレクションからDataRowを取得して、DataRowオブジェクトのRejectChangesメソッドを実行します。これで、DataTableから空白行のDataRowが削除されます。

 

AddingNewプロパティにFalseを設定して初期化します。DataGridEditItemIndexプロパティに「-1」を設定して、BindGridメソッドを実行します。EditItemIndexプロパティに「-1」を設定すると、編集行が通常行として表示されます。

 

Private Sub DataGrid1_CancelCommand(ByVal source As Object,

cccByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs)

cccHandles DataGrid1.CancelCommand

  If Me.AddingNew Then

    Dim dr As DataRow = mdt.Rows(mdt.Rows.Count - 1)

    dr.RejectChanges()

    Session(mCachekey) = mdt

  End If

  Me.AddingNew = False

  DataGrid1.EditItemIndex = -1

  BindGrid()

End Sub

 



[1] DataTableCustomerIDが負になっていますのでOracleデータベースのCustomers表と同期させます。

[2] このストアドプロシージャにはCustomerIDが定義されていませんが、CustomerIDはトリガーで自動採番します。

[3] Oracleデータベースの場合、ExecuteNonQueryメソッドの戻り値は常に「-1」が返ります。