 |

特別寄稿

著/初音 玲 HATSUNE,Akira
■市販コンポーネントとODP.NETの相性を探る
TextBoxコンポーネントやComboBoxコンポーネントのように標準添付の.NET Frameworkコンポーネント以外でもADO.NETと連携する機能がある市販コンポーネントがある。ODP.NETが、ADO.NETに準拠したコンポーネントだとすれば、そのような市販コンポーネントとも接続できるのではないだろうか。Visual Basic時代に既に自明の理となっているように、業務アプリケーションを開発するとき、開発要件にあった市販コンポーネントを利用できるかどうかが、開発効率や品質に大きく影響を与える。もし、ODP.NETと市販コンポーネントの組み合わせが使えるのであれば、業務アプリケーションを開発するときに、非常に心強い。
現在、市販コンポーネントは、かなりの数が市場に出回っている。ADO.NETとの連携機能のあるものに絞り込んでもかなりの数に登るだろう。そのすべてを取り上げる事は難しいので、今回は、グレープシティ社(旧名称、文化オリエント社)の「InputMan for .NET 3.0J」と「El Tabelle for .NET 3.0」を取り上げたいと思う。この両製品は、グレープシティ社のWebサイト(http://www.grapecity.com/Japan/)から機能無制限の期間限定型評価版がダウンロードできるので、製品版が手元にない場合でも評価版で本書の内容を確認する事ができるだろう。
■InputMan for .NET 3.0J
InputMan for .NET 3.0J(インプットマン)は、その名前が示すようにVisual Basic用に市販されていた人気COMコントロールである「InputMan」の設計思想を元に開発した.NET Frameworkコンポーネントだ。
InputManは、入力作業の効率アップに威力を発揮するコンポーネントで、COMコントロール版は、Visual Basicを使った業務アプリケーション開発時に、なくてはならないものの1つだった。Visual Basic .NETになって標準添付のコンポーネントの機能が豊富になり、以前に比べると活躍する機会は減ってきていると思われるが、今回使ってみて感じたのは、標準添付のコンポーネントの機能がいくら豊富になったとしても、まだまだInputManの使いやすさには及ばないところがあるという点だ。
IDEにInputManを登録する
IDEでフォームを定義する場合、コンポーネントをツールボックスからドラッグ&ドロップする。そこで、InputManを使いやすくするためにツールボックスに登録しておきたいと思う。
図1 [GrapeCity]タブを追加
![図1 [GrapeCity]タブを追加](/japan/images/powertools/spotlight/oracle/fig01.png)
ツールボックスで、タブを追加して、そこにグレープシティ社製のコンポーネントを追加する。このカスタマイズ情報は、IDE自体に設定されるので、1度設定すれば、いつでも使うことができる。
標準コンポーネントからInputManに切り替える
■コンポーネントのみを置き換える(サンプルSamp051221)
最初の検証ポイントは、標準コンポーネントとInputManコンポーネントの使い勝手の違いを確認するために、標準コンポーネントをInputManコンポーネントに置き換えただけで、コード部分には手を触れずにアプリケーションを作成できるかだ。今回は、サンプルSamp051214の各コンポーネントを置き換えてみたい。
●サンプルSamp051221プロジェクトの作成
サンプルSamp051214自体を書き換えてしまっても問題はないが、最初からInputManコンポーネントを配置するケースも考慮して、新しいプロジェクトを作成するところから始めてみる。
図2 サンプルSamp051221プロジェクトの作成

サンプルSamp051221のプロジェクトを作成したら、OSP.NETクラスライブラリとログオン画面クラスライブラリの参照設定を追加する。InputManクラスライブラリの参照設定の追加は、まだ行わない。
●サンプルSamp051221の画面定義
図3 サンプルSamp051221の画面定義

新しいプロジェクトを作成したら、サンプルSamp051214の画面定義を参考にして、InputManコンポーネントを配置する。InputManの特徴の1つは、標準コンポーネントのテキストボックスに相当するものが、その入力内容に応じたものに細分化されている点だ。例えば、図3でいえば、EMPNOのようなコード入力欄または名前入力欄についてはテキストコンポーネント(GrapeCity.Win.Input.Edit)としているが、数値入力欄については、数値コンポーネント(GrapeCity.Win.Input.Number)としているところだ。
RDBMSを使ったアプリケーションの場合、最終的にはRDBMS上の表にデータを格納しているので、入力値は、表のドメイン整合性制約に違反したものは格納できない。コンポーネントを入力内容に応じて細分化する事により、より入力値の制限が厳密化できれば、ドメイン整合性制約やプログラミングにより入力値のチェックを行わなくても、最終的にRDBMSに格納できないような不正値は入力すらできないというアプリケーションに仕上げられる。
もちろん、入力値の制限だけがInputManコンポーネントで細分化が行われている理由ではない。
コンポーネントを細分化することで、数値しか入らない入力域ではサブ画面で電卓による計算機能があるなど、入力値の特性に応じた入力作業の効率化機能が付与されている。
図4 標準コントロールとの違いの1例

標準コンポーネントと同等のコントロールにしても、コンボボックスなのに右寄せ表示など見た目を整える機能や、RDBMSを使ったアプリケーションを作成する上での便利な機能が追加されている。
| 1. |
バイト数で入力長制限が可能
標準コンポーネントの場合、文字数指定による入力長制限機能はあるが、半角文字は1バイト、全角文字は2バイトに換算したバイト数指定の入力長制限機能がない。InputManでは文字数指定以外にバイト数指定もできるので、VARCHAR2(80)などのように宣言した項目との相性が良い。
|
| 2. |
NULL値に対応している
文字入力域の場合、RDBMS上でNULL値となっている項目については、1文字も入力がないという状態で表す事が多い。数値についても標準コンポーネントでは「TextBox」として入力域を定義するので、これも1文字も数字入力がない状態として表せる。問題は、日付入力欄だが、サブ画面でカレンダ表示が不要であればテキストボックスで済ませられるが、カレンダ表示が欲しいとなると「DateTimePicker」ではNULL値はサポートされていないため、「TextBox」と「MonthCalendar」を組み合わせて使うなどの工夫が必要になってくる。 |
InputManコンポーネントでは、NULL値の状態を設定できるので、1文字も入力がない状態とNULLの状態を区別できるし、日付についてもNULLの状態(日付欄に何も入力がない状態)をサポートしている。
●サンプルSamp051221のプログラミング
画面定義が完了したら、各種イベントに対応したサブプロシージャをプログラミングするが、コンポーネントの置き換えのみで、どこまでいけるのかを検証したいので、その内容は、サンプルSamp051214と同一にする。ただし、サンプルSamp051214のコードで、ComboBoxオブジェクトを指定しているところがあるため、そこでビルドエラーが発生するので、以下のように書き換える。
### リスト1 コード書換部分(その1) ###
サンプルSamp051214
Private Sub subCboItemSet(ByRef r_cboCtl As ComboBox, _
ByVal v_strSQL As String)
:
(略)
:
End Sub
サンプルSamp051221
Private Sub subCboItemSet(ByRef r_cboCtl As GrapeCity.Win.Input.Combo, _
ByVal v_strSQL As String)
:
(略)
:
End Sub
|
また、DateTimePickerコンポーネントがNULL値をサポートしていないために、DataBindingsコレクションへの追加を”Text”で指定していた部分についても、InputManの日付コンポーネントではNULLをサポートしているので本来の指定である”Value”に戻しておく。
### リスト2 コード書換部分(その2) ###
サンプルSamp051214
Me.txtHIREDATE.DataBindings.Add("Text", m_dsEmp, "EMP.HIREDATE")
サンプルSamp051221
Me.txtHIREDATE.DataBindings.Add("Value", m_dsEmp, "EMP.HIREDATE")
|
●サンプルSamp051221の実行
ビルドエラーが解決したら、実行して動作を検証する。
図5 サンプルSamp051221の実行

IDEまたはビルドしたexeファイルから実行すると、サンプルSamp051221は、残念な事に、検索を行うとエラーが発生してしまう。ODP.NETとInputManの相性問題がまず疑われるが、図5のメッセージボックスのエラー内容からも分かるように、DataSet上のSystem.DateTime型の項目とInputManの間で型変換ができない事が理由のようだ。
InputManのヘルプファイルでも、[日付コントロール]−[データベースに接続する]の説明の中で、NULL値をサポートしているValueプロパティを使う場合の注意点がある。
■InputManコンポーネントを使った場合の注意点(サンプルSamp051222)
InputManのヘルプファイルの情報を元にして、サンプルSamp051221を変更する。説明の都合上、別サンプルSamp051222としているが、サンプルSamp051221を書き換えてしまっても問題はない。
### リスト3 日付コンポーネント連携時の注意点の反映###
Private Function blnFind(ByVal v_strKey As String) As Boolean
Try
Me.ResumeLayout(False)
Me.odpAdapter.SelectCommand.Parameters("EMPNO").Value = Int16.Parse(v_strKey)
'検索
If Not m_dsEmp.Tables("EMP") Is Nothing Then
'初回検索以降
m_dsEmp.Tables("EMP").Clear()
Me.odpAdapter.Fill(m_dsEmp, "EMP")
Else
'初回検索 - 日付コントロールの連携時の決め事
Me.odpAdapter.Fill(m_dsEmp, "EMP")
m_dsEmp.Tables("EMP").Clear()
'
Me.txtENAME.DataBindings.Add("Text", m_dsEmp, "EMP.ENAME")
Me.txtJOB.DataBindings.Add("Text", m_dsEmp, "EMP.JOB")
Me.cboMGR.DataBindings.Add("Text", m_dsEmp, "EMP.MGR")
Me.txtHIREDATE.DataBindings.Add("Value", m_dsEmp, "EMP.HIREDATE")
Me.txtSAL.DataBindings.Add("Text", m_dsEmp, "EMP.SAL")
Me.txtCOMM.DataBindings.Add("Text", m_dsEmp, "EMP.COMM")
Me.cboDEPTNO.DataBindings.Add("Text", m_dsEmp, "EMP.DEPTNO")
")'
Me.odpAdapter.Fill(m_dsEmp, "EMP")
End If
If m_dsEmp.Tables("EMP").Rows.Count > 0 Then
Else
MessageBox.Show("EMPNOに該当するデータは存在しません。", _
Me.Text, _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End If
Catch ex As Exception
MessageBox.Show(ex.Message, _
Me.Text, _
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
Finally
Me.ResumeLayout(True)
End Try
End Function
|
 |
【ポイント1】 : If Not m_dsEmp.Tables("EMP") Is Nothing Then
ヘルプによれば、DataBindingsを実行するときに注意点がある。DataBindingsの実行は、最初にデータを画面に表示するときにのみ実行するので、DataSetにテーブルが作られているかどうかにより、考慮不要な2回目以降か、それとも注意点の考慮が必要な初回かを判定する。
|
|
【ポイント2】 : 初回検索以降
考慮不要な場合、DataSet上のテーブル内容をクリアしてから、FillメソッドによりOracle DatabaseよりDataSetにレコードを取得するだけで、画面に正しくデータが表示できる。
|
|
【ポイント3】 :
初回の場合、FillメソッドによりOracle DatabaseよりDataSetにレコードを取得したら、ClearメソッドによりDataSetのテーブルの内容をクリアして、日付コンポーネントのDataBindingsする項目がNULL値の状態を作り上げてから、DataBindingsする。日付コンポーネント以外には不要な手順だが、コードの視認性をたかめるため、他のコンポーネントについても同じ位置に記述している。
DataBindingsが終わったならば、改めてFillメソッドを実行して、DataSetにレコードを取得する。 |
●サンプルSamp051222の実行
ヘルプに記載されている通りに、ADO.NETとInputManの日付コンポーネントの組み合わせについての注意点に基づいて対応を行えば、ODP.NETと組み合わせた場合もきちんと動作する。
図6 サンプルSamp051222の実行

なお、この注意点の対応だが、今回のサンプルのように単純なSQL文で1レコードのみを表示するようなアプリケーションでは、体感速度的には分からないレベルではあるが、実行開始直後だけとはいえ、Fillメソッドを2回実行しなければならないため、処理速度的に多少不安が残る。
もし、そのあたりも気にしていくのであれば、Fillメソッドによりデータの取得と同時にDataSetのテーブル定義を行うのではなく、DataSetコンポーネントを使って、設計時にテーブル定義を済ませてしまい、DataBindingsではなく、コンポーネントの(DataBindings)プロパティで指定するようにすれば良いだろう。この方法を使ったサンプルもSamp051224として収録してあるので、詳しくはそちらを見てもらいたい。
|
 |
|
|