DataGridにレコードの編集機能を付加するには

 

  DataGridにレコードの編集機能を付加するサンプル(手動方式)

 

DataGridにレコードの編集機能を付加するサンプル(手動方式)

 

 

このサンプルは、DataGridにレコードの編集機能を追加しています。DataGridから編集ボタンをクリックすると得意先名、担当者名、電話番号がTextBoxに表示されますので編集後、確定ボタンをクリックします。中止ボタンをクリックすると編集がキャンセルされます。このサンプルでは、確定ボタンをクリックしたときデータベースへの書き込みをSQLコマンドで行っています。

 

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

 

  DataGridにレコードの編集機能を付加する方法

  DataGridBoundColumnの使い方

  DataGridEditCommandColumnの使い方

  DataGridOnEditCommandイベントの使い方

  DataGridOnUpdateCommand, OnCancelCommandイベントの使い方

  DataGridから編集したレコードをSQLコマンドでデータベースに反映する方法

 

サンプルの行85-125では、DataGridを定義しています。行88では、OnEditCommandイベントを登録しています。このイベントは、DataGridから編集ボタンをクリックすると発生します。行89では、OnUpdateCommandイベントを登録しています。このイベントは、DataGridから確定(更新)ボタンをクリックすると発生します。確定ボタンは、レコードが編集モードのときに表示されます。行90では、OnCancelCommandイベントを登録しています。このイベントは、DataGridから中止ボタンをクリックすると発生します。中止ボタンは、レコードが編集モードのときに表示されます。行100では、EditItemStyleで編集行のスタイルを設定しています。CssClassプロパティには、CSSのクラス名を設定しています。CSSのクラスdgrdEditItemStyleは、外部ファイルstyle1.cssに登録されています。行101-124<Columns>…</Columns>では、BoundColumn, EditCommandColumnを定義しています。行102-106では、BoundColumnで得意先IDを表示しています。DataFieldプロパティには、得意先IDのフィールド名(CustomerID)を設定しています。HeaderTextプロパティには、「ID」を設定しています。ReadOnlyプロパティにTrueを設定して読み込み専用にしています。この場合、編集ボタンをクリックしても得意先IDを編集することができません。行107-109では、BoundColumnで得意先名を表示しています。DataFieldプロパティには、得意先名のフィールド名(CompanyName)を設定しています。HeaderTextプロパティには、「得意先名」を設定しています。このカラムでは、ReadOnlyプロパティを省略していますのでFalseが採用されます。編集ボタンをクリックしたとき、ReadOnlyプロパティにFalseが設定されているカラムが編集対象になります。以下、同様に担当者名、電話番号を表示しています。行116-123では、EditCommandColumnで編集ボタン、確定(更新)ボタン、中止ボタンを定義しています。確定ボタンと中止ボタンは、編集モードのときに表示されます。

 

85: <asp:DataGrid id="dgrdCustomers" runat="server"
 88:   OnEditCommand="dgrdCustomers_EditCommand"
 89:   OnUpdateCommand="dgrdCustomers_UpdateCommand"
 90:   OnCancelCommand="dgrdCustomers_CancelCommand"

:::: >
100:   <EditItemStyle CssClass="dgrdEditItemStyle" />
101:   <Columns>
102:     <asp:BoundColumn
103:       DataField="CustomerID"
104:       HeaderText="ID"
105:       ReadOnly="True"
106:       ItemStyle-HorizontalAlign="Right" />
107:     <asp:BoundColumn
108:       DataField="CompanyName"
109:       HeaderText="
得意先名" />

::::
116:     <asp:EditCommandColumn
117:       ButtonType="PushButton"
118:       EditText="
編集"
119:       UpdateText="
確定"
120:       CancelText="
中止">
121:       <ItemStyle BackColor="Yellow"
122:         HorizontalAlign="Center" />
123:     </asp:EditCommandColumn>
124:   </Columns>
125: </asp:DataGrid>

 

Page_Load()イベントの行13-14では、OleDbConnection, OleDbDataAdapterのインスタンスを生成してモジュールレベルの変数に保存しています。行15では、Cacheのキーを生成して変数に保存しています。行17-18は、ページが最初にロードされたときに実行されます。Sub LoadData()では、得意先テーブルのレコードを抽出してDataTableを生成します。DataTableは、ポストバックされてときに再使用できるようにメモリ上にキャッシュします。Sub BindDataGrid()では、DataTableDataGridにバインドして表示します。行20-23は、ページがポストバックされたときに実行されます。行20では、メモリ上にキャッシュされたDataTableを変数に保存しています。キャッシュが無効になっているときは、Sub LoadData()を呼び出してDataTableを生成します。

 

11: Sub Page_Load()
 12:   Dim strSQL As String = "Select top 10 * From Customers Order by CustomerID"
 13:   mcon = New OleDbConnection(ConfigurationSettings.AppSettings("conStringNw"))
 14:   mda = New OleDbDataAdapter(strSQL, mcon)
 15:   mstrCacheKey = "Customers" & Request.Path
 16:   If Not IsPostBack Then
 17:     LoadData()
 18:     BindDataGrid()
 19:   Else
 20:     mdt = Cache(mstrCacheKey)
 21:     If mdt Is Nothing Then
 22:       LoadData()
 23:     End If

 24:   End If
 25: End Sub

 

Sub LoadData()では、OleDbDataAdapterFill()メソッドで得意先テーブルからレコードを抽出してDataSetに格納します。さらに、DataSetTablesコレクションから得意先テーブルのDataTableを生成して変数に保存します。ここで生成したDataTableは、ポストバックされたときに再使用するためにWebサーバのメモリ上にキャッシュします。

 

27: Sub LoadData()
 28:   Dim ds As New DataSet()
 29:   mda.Fill(ds,"Customers")
 30:   mdt = ds.Tables("Customers")
 31:   Cache(mstrCacheKey) = mdt
 32: End Sub

 

Sub BindDataGrid()では、DataGridDataSourceプロパティに得意先テーブルのDataTableを設定して、DataBind()メソッドでバインドします。これで、得意先テーブルがDataGrid上に表示されます。

 

34: Sub BindDataGrid()
 35:   With dgrdCustomers
 36:     .DataKeyField="CustomerID"
 37:     .DataSource = mdt
 38:     .DataBind()
 39:   End With
 40: End Sub

 

DataGridから編集ボタンをクリックすると、OnEditCommandイベントが発生します。このイベントでは、DataGridCommandEventArgsItem.ItemIndexプロパティをDataGridEditItemIndexプロパティに設定して編集モードに切り替えています。Item.ItemIndexには、編集ボタンをクリックした行のインデックス番号が格納されています。DataGridEditItemIndexプロパティにインデックス番号を設定すると、その行が編集モードになります。Sub BindDataGrid()を呼び出して、DataGridをバインドすると編集ボタンをクリックした行が編集モードで表示されます。編集モードに切り替わると、得意先名、担当者名、電話番号がTextBox上に表示されて編集可能になります。編集ボタンは、確定ボタンと中止ボタンに切り替わります。

 

42: Sub dgrdCustomers_EditCommand(s As Object, e As DataGridCommandEventArgs)
 43:   dgrdCustomers.EditItemIndex = e.Item.ItemIndex
 44:   BindDataGrid()
 45: End Sub

 

レコードを編集して確定(更新)ボタンをクリックすると、OnUpdateCommandイベントが発生します。このイベントでは、編集したレコードをデータベースに反映します。行48-49では、得意先テーブルのレコードを更新するSQLを生成しています。レコードを更新するには、SQLUpdateステートメントを使用します。行50では、OleDbCommandのインスタンスを生成しています。引数には、SQLコマンドとOleDbConnectionを指定します。行52では、DataGridDataKeysプロパティから主キー(CustomerID)を取得して変数に保存しています。DataKeysの引数には、アイテムのインデックス番号を指定します。行53-55では、DataGridCommandEventArgsクラスのItem.Cells().Controls()プロパティから得意先名、担当者名、電話番号のTextBoxを取得してTextプロパティの値を変数に保存しています。つまり、編集データを取得して格納しています。行57-62With…End Withでは、SQLのパラメータ変数に編集した値を設定しています。行64-66では、OleDbConnectionOpen()メソッドでデータベースを開いて、OleDbCommandExecuteNonQuery()メソッドでSQLUpdateステートメントを実行して、データベースを閉じています。これで、DataGridから編集したレコードがデータベースに反映されます。行68-70では、編集モードを解除して得意先テーブルから抽出したレコードを再表示しています。DataGridEditItemIndexプロパティに-1を設定すると編集モードが解除されます。

 

47: Sub dgrdCustomers_UpdateCommand(s As Object, e As DataGridCommandEventArgs)
 48:   Dim strSqlUpdate As String = "Update Customers Set CompanyName=@CompanyName," & _
 49:     "ContactName=@ContactName, Phone=@Phone Where CustomerID=@CustomerID"
 50:   Dim cmd As New OleDbCommand(strSqlUpdate,mcon)
 52:   Dim intCustomerID As Integer = dgrdCustomers.DataKeys(e.Item.ItemIndex)
 53:   Dim strCompanyName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text
 54:   Dim strContactName As String = CType(e.Item.Cells(2).Controls(0), TextBox).Text
 55:   Dim strPhone As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text
 57:   With cmd.Parameters
 58:     .Add("@CompanyName",strCompanyName)
 59:     .Add("@ContactName",strContactName)
 60:     .Add("@Phone",strPhone)
 61:     .Add("@CustomerID",intCustomerID)
 62:   End With
 63:
 64:   mcon.Open()
 65:   cmd.ExecuteNonQuery()
 66:   mcon.Close()
 67:
 68:   dgrdCustomers.EditItemIndex = -1
 69:   LoadData()
 70:   BindDataGrid()
 71: End Sub

 

DataGridから中止ボタンをクリックしたときは、OnCancelCommandイベントが発生します。このイベントでは、編集モードを解除して編集前のデータを再表示します。DataGridEditItemIndexプロパティに-1を設定すると編集モードが解除されます。Sub BindDataGridでは、DataGridDataTableをバインドします。

 

73: Sub dgrdCustomers_CancelCommand(s As Object, e As DataGridCommandEventArgs)
 74:   dgrdCustomers.EditItemIndex = -1
 75:   BindDataGrid()

76: End Sub

 

このサンプルでは、編集したレコードをデータベースに反映するのに以下のようなUpdateステートメントを使用しています。Where句では、CustomerID=@CustomerIDを指定していますので得意先IDでレコードを検索して更新します。得意先IDでレコードを検索して更新する場合、他のクライアントと競合するとレコードが2重更新される可能性があります。レコードの2重更新を防止する方法については、後述するTipsを参照してください。

 

Update Customers

Set CompanyName=@CompanyName ContactName=@ContactName, Phone=@Phone

Where CustomerID=@CustomerID

 

Tip

レコードの2重更新を防止するには

 

たとえば、得意先テーブルの2重更新を防止するには新規フィールドConcurrencyIDを追加してレコードの更新回数を管理します。DataGirdから確定ボタンをクリックしてレコードを更新するときは、以下のようなSQLを使用します。

 

Update Customers

Set CompanyName=@CompanyName ContactName=@ContactName, Phone=@Phone

  ConcurrencyID = ConcurrencyID + 1

Where CustomerID=@CustomerID And ConcurrencyID=@ConcurrencyID

 

@CustomerIDには、更新するレコードの得意先IDを設定します。@ConcurrencyIDには、更新前に取得したConcurrencyIDを設定します。他のクライアントからすでに更新されているときは、ConcurrencyIDが不一致になりますので更新されません。レコードが更新されたか調べるには、OleDbCommandExecuteNonQuery()メソッドの戻り値を調べます。戻り値が0のときは、更新されていませんのでDataGridに最新のデータを表示して再試行させます。

 

更新前のConcurrenyIDは、DataGridBoundColumnで埋め込んでおきます。Visibleプロパティには、Falseを設定して非表示にします。

 

<asp:BoundColumn

  DataField=”ConcurrencyID”

  Visible=”False” />

 

 

 

  DataGridにレコードの編集機能を付加するサンプル(自動方式)

 

DataGridにレコードの編集機能を付加するサンプル(自動方式)

 

このサンプルは、DataGridにレコードの編集機能を追加しています。機能的には、すでに解説した「手動方式」と同じです。このサンプルでは、DataGridのレコードを編集して確定ボタンをクリックしたとき、OleDbDataAdapterUpdate()メソッドを使用してデータベースに反映しています。つまり、データベースの更新処理を自動化しています。

 

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

 

  OleDbCommandBuilderの使い方

  OleDbDataAdapterUpdate()メソッドの使い方

 

サンプルの行81-121では、DataGridを定義しています。行97-120では、<Columns>…</Columns>内にBoundColumn, EditCommandColumnで得意先ID、得意先名、担当者名、電話番号、編集ボタンを表示しています。

 

81: <asp:DataGrid id="dgrdCustomers" runat="server"
 90:   ::: >
 97:   <Columns>

::::
120:   </Columns>
121: </asp:DataGrid>

 

Sub Page_Load()の行13では、得意先テーブルからレコードを抽出するSQLを生成しています。行14-15では、OleDbConnection, OleDbDataAdapterのインスタンスを生成しています。OleDbConnectionの引数には、Web.configに登録されているデータベース接続情報を指定しています。OleDbDataAdapterの引数には、SQLOleDbConnectionを指定しています。行16では、OleDbCommandBuilderのインスタンスを生成しています。引数には、OleDbDataAdapterを指定します。OleDbCommandBuilderは、SQLInsert, Update, Deleteステートメントを生成します。SQLコマンドは、行13Selectステートメントをベースに生成します。このサンプルでは、以下のようなSQLが生成されます。

 

Insert用のSQL:

INSERT INTO Customers( CompanyKana , CompanyName , ContactName ,

ContactTitle , PostalCode , KenKana , Ken , Address1 , Address2 , Phone , Fax ,

ConcurrencyID ) VALUES ( ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? )

 

UpdateSQL:

UPDATE Customers SET CompanyKana = ? , CompanyName = ? ,

ContactName = ? , ContactTitle = ? , PostalCode = ? , KenKana = ? , Ken = ? ,

Address1 = ? , Address2 = ? , Phone = ? , Fax = ? , ConcurrencyID = ?

WHERE ( (CustomerID = ?)

AND ((? IS NULL AND CompanyKana IS NULL) OR (CompanyKana = ?))

AND ((? IS NULL AND CompanyName IS NULL) OR (CompanyName = ?))

AND ((? IS NULL AND ContactName IS NULL) OR (ContactName = ?))

AND ((? IS NULL AND ContactTitle IS NULL) OR (ContactTitle = ?))

AND ((? IS NULL AND PostalCode IS NULL) OR (PostalCode = ?))

AND ((? IS NULL AND KenKana IS NULL) OR (KenKana = ?))

AND ((? IS NULL AND Ken IS NULL) OR (Ken = ?))

AND ((? IS NULL AND Address1 IS NULL) OR (Address1 = ?))

AND ((? IS NULL AND Address2 IS NULL) OR (Address2 = ?))

AND ((? IS NULL AND Phone IS NULL) OR (Phone = ?))

AND ((? IS NULL AND Fax IS NULL) OR (Fax = ?))

AND ((? IS NULL AND ConcurrencyID IS NULL) OR (ConcurrencyID = ?)) )

 

Delete用のSQL:

DELETE FROM Customers

WHERE ( (CustomerID = ?)

AND ((? IS NULL AND CompanyKana IS NULL) OR (CompanyKana = ?))

::::

AND ((? IS NULL AND ConcurrencyID IS NULL) OR (ConcurrencyID = ?)) )

 

OleDbDataAdapterUpdate()メソッドは、ここで生成されたSQLを使用してレコードを追加、更新、削除します。Update/DeleteステートメントのWhere句では、各フィールドの値が更新前の内容と一致するときのみレコードを更新/削除するようにしています。これによりレコードの2重更新が防止されます。ConcurrencyIDを使用するときは、以下のようなSQLを使用することもできます。

 

UPDATE Customers SET CompanyKana = ? , CompanyName = ? ,

ContactName = ? , ContactTitle = ? , PostalCode = ? , KenKana = ? , Ken = ? ,

Address1 = ? , Address2 = ? , Phone = ? , Fax = ? , ConcurrencyID = ConcurencyID+1

WHERE ( (CustomerID = ?) AND (ConcurrencyID = ?))

 

 

19-20は、ページが最初にロードされたときに実行されます。Sub LoadData()では、得意先テーブルのレコードを抽出してDataTableを生成します。Sub BindDataGrid()では、DataTableDataGridにバインドして表示します。行22-25は、ページがポストバックされたときに実行されます。行22では、キャッシュされたDataTableを変数に保存しています。キャッシュが無効になっているときは、Sub LoadData()を呼び出してDataTableを生成します。

 

12: Sub Page_Load()
 13:   Dim strSQL As String = "Select top 10 * From Customers Order by CustomerID"
 14:   mcon = New OleDbConnection(ConfigurationSettings.AppSettings("conStringNw"))
 15:   mda = New OleDbDataAdapter(strSQL, mcon)
 16:   mcb = New OleDbCommandBuilder(mda)
 17:   mstrCacheKey = "Customers" & Request.Path
 18:   If Not IsPostBack Then
 19:     LoadData()
 20:     BindDataGrid()
 21:   Else
 22:     mdt = Cache(mstrCacheKey)
 23:     If mdt Is Nothing Then
 24:       LoadData()
 25:     End If
 26:   End If
 27: End Sub

 

DataGridから確定(更新)ボタンをクリックすると、OnUpdateCommandイベントが発生します。このイベントでは、編集したレコードをデータベースに反映しています。行51では、DataGridDataKeysプロパティから得意先IDを取得して変数に保存しています。行52-54では、DataGridから得意先名、担当者名、電話番号の編集データを取得して変数に保存しています。行55では、DataTableRowsコレクションのFind()メソッドで得意先レコードを検索しています。得意先レコードが見つかったときは、DataRowが生成されます。行57-59では、DataRowの得意先名、担当者名、電話番号を編集データで更新しています。行64では、OleDbDataAdapterUpdate()メソッドでDataTableをデータベースに反映しています。Update()メッドは、OleDbCommandBuilderで生成されたSQLを使用してDataTableのレコードをデータベースに書き込みます。行65では、DataGridEditItemIndexプロパティに-1を設定して編集を解除しています。行66では、Sub BindDataGrid()を呼び出してDataGridDataTableをバインドしています。

 

50: Sub dgrdCustomers_UpdateCommand(s As Object, e As DataGridCommandEventArgs)
 51:   Dim intCustomerID As Integer = dgrdCustomers.DataKeys(e.Item.ItemIndex)
 52:   Dim strCompanyName As String = CType(e.Item.Cells(1).Controls(0), TextBox).Text
 53:   Dim strContactName As String = CType(e.Item.Cells(2).Controls(0), TextBox).Text
 54:   Dim strPhone As String = CType(e.Item.Cells(3).Controls(0), TextBox).Text
 55:   Dim dr As DataRow = mdt.Rows.Find(intCustomerID)
 56:   If Not (dr Is Nothing) Then
 57:     dr("CompanyName") = strCompanyName
 58:     dr("ContactName") = strContactName
 59:     dr("Phone") = strPhone
 60:   End If
 64:   mda.Update(mdt)
 65:   dgrdCustomers.EditItemIndex = -1
 66:   BindDataGrid()
 67: End Sub

 

このサンプルでは、OleDbCommandBuilderで生成されたSQLを使用していますが、ストアドプロシージャを使用してデータベースに反映することもできます。この場合、OleDbDataAdapterInsertCommand, UpdateCommand, DeleteCommandプロパティにストアドプロシージャを設定してからUpdate()メソッドを実行します。

ASP.NET DataGridのホームへ戻る