はじめに
前回は、オブジェクト指向プログラミングによってサンプルソフトウェアを作成しました。
このサンプルを作成するために、各テーブルのフィールドに応じたクラスや、データにアクセスさせるためのクラスを作成しました。
これによって、オブジェクト指向プログラミングがどのようなものなのかを体感していただけたかと思います。
しかし、実際に業務で使用するフィールドやテーブルの数だけ、同様のクラスを作ることは困難です。
そこで今回はDataSetやComponentという方法を用いて、前回開発したソフトウェアの開発の省力化についてをご説明したいと思います。
DataSetとは?
DataSetは、VB6で提示したサンプルソフトウェアで使用したRecordSetオブジェクトと似ています。
データレコードをDataSetオブジェクトの中のDataTableオブジェクトに格納して、編集した後にデータテーブルに書き戻すという一連の流れを容易に実現できます。
Componentとは?
再利用性の高いオブジェクトを部品化したもの、と表現するのが理解しやすいかと思います。
例えば、TextBoxなどのユーザーコントロールは、ユーザーインターフェイスを持ったコンポーネントです。
一方でタイマーコントロールのようなユーザーインターフェイスを持たないコンポーネントも存在します。
しかし、どちらのコンポーネントもコンテナに配置できます。
作成するにあたっての注意
今回、コンポーネントを多用しますが、個々のコンポーネントを作成した後にビルドを成功させないとツールボックスにコンポーネントが出現しません。
そこで、今回の内容を実践する場合は、必ず新しいプロジェクトを用意してください。
以前に使ったプロジェクトを利用した場合、変更の仮定でエラーが発生する恐れがあります。
DataSetの作成
新規作成
DataSetを新規作成する手順は次の通りです。
最初に、プロジェクト名を選択後に右クリックしてメニューを表示します。
ここから「追加」「新しい項目」と順にクリックしてください。
「新しい項目の追加」ダイアログボックスが表示されたら、データセットを選択します。
今回も名前は「DataSet1」のままでよいでしょう。
[追加]ボタンを押すことでDataSetが生成されます。
サーバーエクスプローラーにデータベースを接続
DataSetを編集してテーブルを追加します。
DataSetの編集画面に表示されているメッセージの「サーバーエクスプローラー」のリンク部分をクリックして、サーバーエクスプローラーを開きます。
データ接続を選択後に右クリックしてメニューを表示します。
ここから「接続の追加」をクリックします。
「接続の追加」ダイアログボックスが表示されたら、データベースファイル名を指定します。
[テスト接続]ボタンを押して問題なく接続できることを確認後に[OK]ボタンをクリックしてください。
データテーブルを編集
DataSetにデータテーブルをマッピングします。
サーバーエクスプローラーの画面からMyTableをドラッグして、DataSet1のデザイナ上でドロップします。
これによって、データ本体を格納するMyTableオブジェクトと、データベースにアクセスするためのMyTableAdapterオブジェクトが作成されます。
この状態で、一旦ビルドします。
ビルドに成功することで、フォームエディタ画面が表示されている状態でツールボックスを開いた際に、先ほど作成したオブジェクトがコンポーネントとして追加さます。
Logicの作成
次にLogicコンポーネントを作成します。
新規作成
ソリューションエクスプローラーから、DataSetを登録した方法と同様に、Logicというコンポーネントを追加してください。
上記のように、DataSet1、MyTableTableAdapter、BindingSourceコンポーネントをLogicコンポーネントのコンテナに配置します。
各コンポーネントオブジェクトの名前も、上記と同様になっていることを確認してください。
BindingSource1の設定
BindingSourceは、DataSet1のMyTableオブジェクトとフォームオブジェクト上のユーザーコントロールとのデータバインディングを行う際に便利なコンポーネントです。
上記のように、DataSourceにdataSet1を、DataMemberにMyTableを設定します。
これによって、dataSet1.MyTableオブジェクトはBindingSourceオブジェクトにバインドされたことになります。
BindingSourceオブジェクトとユーザーコントロールのバインディングの方法は、次項でご説明します。
コードの作成
Logic クラスのコードは次のようになります。
なお、今回はあえて、Fillメソッドによって全レコードをDataSetオブジェクトに格納してみたいと思います。
中で使用するオブジェクトが異なるため、前回作成したLogicクラスとは少々違っています。
クラスの継承について
基本クラスがComponentになっています。
C#では継承できるクラスは1つだけになるので、前回のようにNotifyPropertyChangedクラスを自作して実装を書いたものを利用することはできません。
ただし、インターフェイスは複数継承できます。
そこで、INotifyPropertyChangedインターフェイスを継承してNotifyPropertyChangedクラスの実装をLogicクラスに持たせています。
コンストラクタ
今回のコンストラクタは、引数のないコンストラクタと、IContainer型引数を受け取るコンストラクタの2つ存在します。
これらのコンストラクタは自動生成されたものです。
C#では、コンストラクタに限らず、引数の型や数が異なる場合に同じメソッド名を複数持つことができます。
これをOverloadと呼びます。
BindingSourceプロパティ
VB6では、フォームオブジェクトに配置されたコントロールへ外部からアクセスすることができました。
しかしC#では、カプセル化という意味から、必要に応じて公開するという意味で非公開になっています。
BindingSourceはフォーム上のユーザーコントロールとバインドさせる必要があるため、このコントロールのオブジェクトをプロパティとして公開します。
DataSetのデータを充填する
フォームが開いたタイミングで、DataSetにデータを充填できるようにFillメソッドを作成して公開します。
this.myTableTableAdapter.Fillによって、全レコードがthis.dataSet1.MyTableオブジェクトに充填されます。
また、読みこまれたレコードは複数あるため、現在どのレコードを指しているのかに応じてCodeプロパティの値をセットするためのメソッドを呼び出します。
追加処理
bindingSource1のFindメソッドによって、番号列の値がthis.Codeプロパティの値を探して、その要素番号を取得しています。
bindingSource1オブジェクトはdataSet1.MyTableオブジェクトとバインドされているため、Fillメソッドによって充填したデータを参照できます。
要素番号が0以上なら、既に存在している値を追加しようとしていることになるため、例外エラーを発生させます。
その後、新しい行をbindingSource1.AddNewメソッドから作成します。
作成された行オブジェクトはobject型なので、これをGetMyTableRowメソッドによってDataSet1.MyTableRow型に変換します。
最後に、bindingSource1のEndEditメソッドで編集を終了させて、dataSet1.MyTableオブジェクトの内容をデータベースに反映させます。
読み込み
Positionプロパティに要素番号値を格納することで、現在指しているレコードを変更できます。
Codeプロパティに値をセットする
bindingSource1オブジェクトのCurrentプロパティは、現在指しているレコードオブジェクトを格納しています。
このレコードの番号の値をCodeプロパティにセットしています。
型の変換
以下は、指定されたオブジェクト型の値をDataSet1.MyTableRow型に変換した結果を返すためのメソッドです。
変換できない場合はnull値を返します。
C#はタイプセーフな言語です。
objectはすべての型から継承されている型なので、すべての変数はobject型に格納できます。
一方で、一度object型に格納したオブジェクトを元の型に代入するような場合には、キャスト(型変換)が必要です。
ただし、object型には何でも代入できてしまうため、確実にキャストできる保証はありません。
キャストに失敗すると、実行時に例外エラーが発生してしまいます。
上記のコードはas演算子を使って、valueをDataRowView型にキャストした結果をDataRowView型のvという変数に格納します。
この時、キャストに失敗した場合、vにはnullが格納されます。
Form1の作成
Form1は、プロジェクトを作成した際に自動的に作られています。
Logicコンポーネントの配置
Form1のフォームエディタを開いて、TextBoxやButtonコントロールを配置する方法と同様に、LogicコンポーネントをツールボックスからForm1に配置します。
配置は、Form1のイメージ上ではなく、エディタの下部に表示されます。
なお、Logicコンポーネントをツールボックスに存在させるためには、Logicクラスを作成した後に、一度ビルドを成功させる必要があります。
コードの作成
コードは以下の通りです。
基本的には、以前作成したForm1と同様ですが、logicフィールド変数はフォームエディタ側でコンポーネントとして設定されているためコードで記述していません。
コンストラクタ
今回も、各TextBoxへのバインディングをコンストラクタで指定しています。
バインディングするオブジェクトは、RowではなくBindingSourceになります。
フォームロードイベント時の処理
以下のコードによって、フォームロードイベントによって、DataSetにデータが充填されます。
最後に
今回は、DataSetを使う方法をご紹介しました。
ここまで理解できれば、実際にC#を使って仕事が行えるだけの下準備は十分にできていると言えるでしょう。
本連載は、今回が最後になります。
VB6で実際に活躍されているプログラマの方に向けた内容ということもあり、基本的な入門書という形に捕らわれることなく、サンプルコードを多用した説明をさせていただくことで、多くの内容を盛り込むことができました。
本連載を読んでくださった多くの方がC#によるプログラミングを楽んでいただけることを願っています。
最後に、本連載を読んでくださった皆さん、連載の機会を与えてくださった技術評論社と担当の方々を始めとする多くの皆さんに心からお礼を申し上げます。
ありがとうございました。