金宏 和實(かねひろ かずみ)

 富山県高岡市 株式会社イーザー副社長。炊飯器くんを買い替えました。といっても高価なものではなく,セールで5,800円程度で売っていたものです。以前の炊飯器では「xx時に炊き上がるようにするには」と妻が時間を指折り数えてタイマーをセットしていましたが,新しい炊飯器は「xx時に炊き上がるように」と簡単にセットすることができます。こんな安い炊飯器もソフトウエアの力で便利になっているのだと実感できました。

 ADO.NETは,米Microsoftが提供する.NET Frameworkで,各種データベースへの接続機能を提供するソフトウエア・コンポーネントです。Visual Studio 2005で利用するADO.NETのバージョンはまだ2.0ですが,ADO.NETは多機能で複雑です。どの機能をどんなときに使うべきかを今回から考えていきたいと思います。

 前回は,プロジェクトにデータソースを追加して,自動的に作られたクラスを利用してDataTableを作成しました。データベースにはSQL Server 2005 Express Editionを使いました(リスト1)。DataTableをDataGridViewのデータソースに指定することで一覧表示が簡単にできましたね。


Private Sub Form1_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load
  Dim dt = New RaceDBDataSet.TeamsDataTable()
  Dim da = New RaceDBDataSetTableAdapters.TeamsTableAdapter()

  da.Fill(dt)
  DataGridView1.DataSource = dt
End Sub
リスト1●フォームのLoadプロシジャで,DataTableをDataGridViewのデータソースに指定する

 データベースとデータテーブルの関係は(図1)のようになります。

図1●データベースとデータテーブルの関係
図1●データベースとデータテーブルの関係

 前回は表示するだけだったので,単にレコードセットを作成して,それをDataGridViewのデータソースにしているだけのように思えたでしょう。実際には,TableAdapterを介して作成されたTeamsDataTableが所属するRaceDBDataSetは,ローカルPCのメモリー上に作成したインメモリー・データベースなのです。

 インメモリーとはいえ,データベースなのですから,当然,TeamsDataTableに対して挿入(Insert),更新(Update),削除(Delete)というデータ操作をすることができます。

 ADO.NETを使ったデータベースの更新処理で最も簡単なのは,データソースを作成した際に自動生成されたクラスを使ってテーブルを更新する方法です。文法ミスを犯しやすいSQL文を扱う必要がありませんし,短いコードで更新処理を記述できます。

カレント行のデータをテキストボックスに表示

 さっそくプログラムを作ってみましょう。まずはフォームにコンポーネントを配置します(図2)。最初にSplitContainerを配置して,フォームを縦方向に二分割します。上半分には前回作成したフォームと同様に,DataGridViewと,検索用のテキストボックス,検索処理を起動するボタンを配置します。

図2●フォームに配置するコンポーネント
図2●フォームに配置するコンポーネント

 データを取得し,DataGridViewに表示するコードは,あとで修正しますが,とりあえず最初は前回と同じコードにしておきます(リスト2)。これは,テキストボックスに何も入力されていないときは,データソース作成時に自動生成されたFillメソッドを呼び出し,チーム名の一部が入力されていたらFillByTeamNameメソッドを呼び出す処理でした(詳細は本連載第8回を参照)。


Private Sub dispView()

  da.Fill(dt)

  If txtName.Text = "" Then
    da.Fill(dt)
  Else
    da.FillByTeamName(dt, "%" & txtName.Text & "%")
  End If

  DataGridView1.DataSource = dt
  DataGridView1.Columns(2).Visible = False
  DataGridView1.Columns(3).Visible = False
  DataGridView1.Columns(4).Visible = False
  DataGridView1.Columns(5).Visible = False
  DataGridView1.Columns(0).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight
  DataGridView1.Columns(6).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight
  DataGridView1.Columns(7).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight
  DataGridView1.Columns(8).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight
  DataGridView1.Columns(9).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight
  DataGridView1.Columns(10).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight
  DataGridView1.Columns(11).DefaultCellStyle.Alignment = _
    DataGridViewContentAlignment.MiddleRight

  DataGridView1.Columns(7).DefaultCellStyle.Format = "#,##0.00"
  DataGridView1.Columns(8).DefaultCellStyle.Format = "#,##0.00"
  DataGridView1.Columns(10).DefaultCellStyle.Format = "#,##0.00"
  DataGridView1.Columns(11).DefaultCellStyle.Format = "#,##0.00"

  DataGridView1.Columns(0).HeaderText = "NO"
  DataGridView1.Columns(1).HeaderText = "チーム名"
  DataGridView1.Columns(6).HeaderText = "出走順1"
  DataGridView1.Columns(7).HeaderText = "タイム1"
  DataGridView1.Columns(8).HeaderText = "ぺナ1"
  DataGridView1.Columns(9).HeaderText = "出走順2"
  DataGridView1.Columns(10).HeaderText = "タイム2"
  DataGridView1.Columns(11).HeaderText = "ぺナ2"
End Sub
リスト2●DataGridViewにデータを表示するdispViewプロシジャ

 Fillメソッドでは,WHERE句なしのSELECT文を実行し,FillByTeamNameメソッドでは,WHERE句でlike演算子を使った部分一致の検索を実行します。

 このDispViewサブ・プロシジャをフォーム・ロード時と検索ボタン・クリック時に呼び出します。前回のサンプル・プログラムは,こうして一覧表示を実現していました。

 今回は,前回とは異なり,TeamsDataTableクラスのオブジェクトdtとTeamsTableAdapterクラスのオブジェクトdaを,クラス宣言の次にPrivateで宣言します(リスト3)。それぞれをForm3クラス全体で使えるようにするためです。


Public Class Form3
  Private dt = New RaceDBDataSet.TeamsDataTable()
  Private da = New RaceDBDataSetTableAdapters.TeamsTableAdapter()
リスト3●TeamsTableAdapterクラスとTeamsTableAdapterクラスのオブジェクトをPrivateで宣言する

 フォームの下半分で,一覧表示で選択した行の各フィールドの値をテキストボックスに表示するようにしましょう。DataGridViewのRowEnterイベントで,dispRowサブ・プロシジャを呼び出します(リスト4)。RowEnterイベントは,行がフォーカスを受け取り,現在の(カレント)行になったときに発生します。


Private Sub DataGridView1_RowEnter(ByVal sender As System.Object, _
  ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) _
  Handles DataGridView1.RowEnter
  dispRow()
End Sub

Private Sub dispRow()
  For Each row As DataGridViewRow In DataGridView1.SelectedRows
    txtNo.Text = row.Cells(0).Value
    txtTeamName.Text = row.Cells(1).Value
    txtRepresent.Text = row.Cells(2).Value
    ' 以下,nullを許容する項目
    txtTelNo.Text = Trim(row.Cells(3).Value & "")
    txtEmail.Text = row.Cells(4).Value & ""
    txtNote.Text = row.Cells(5).Value & ""
    txtOrder1.Text = row.Cells(6).Value
    txtTime1.Text = row.Cells(7).Value
    txtPena1.Text = row.Cells(8).Value
    txtOrder2.Text = row.Cells(9).Value
    txtTime2.Text = row.Cells(10).Value
    txtPena2.Text = row.Cells(11).Value
    lblResult1.Text = row.Cells(7).Value + row.Cells(8).Value
    lblResult2.Text = row.Cells(10).Value + row.Cells(11).Value
  Next
End Sub
リスト4●DataGridViewのRowEnterイベントで,行の内容をテキストボックスに代入するdispRowプロシジャを呼び出す

 dispRowサブ・プロシジャでは,行(row)の内容をテキストボックスに代入しています。データベースの列(フィールド)がCells(n)と表現されていることがわかるでしょう。For Each文で行を処理しているので,複数行が対象になっているように見えますが,前回説明したようにDataGridViewのMultiSelectプロパティはFalseに設定してあるので,処理対象となる行は常に一行です。

 注意してほしいのは,テーブル定義で「Nullを許容する」としている列の扱いです。この列に本当に値が入っていないと,代入の際にDBNullをStringに変換しようとするところでエラーになってしまいます。そこで,&""のようにして空文字を連結しています。

 結果を表示するところでは,タイムとペナルティの足し算で求めています(図3)。

図3●結果のラベルには,タイムとペナルティの和を表示する
図3●結果のラベルには,タイムとペナルティの和を表示する
[画像のクリックで拡大表示]

 さて,SplitContainerを使った理由は,実行時に,分割したフォームの上部と下部の比率を変更できるからです。一覧表示の行数が多いときは上半分を広げて見やすくし,データを編集するときには下半分を広げて入力しやすくするといった使い方ができます。