エンティティクラスオブジェクトとデータベースのデータのマッピング

DataReaderやDataTableにデータベースから取得したデータを、定義したエンティティクラスのオブジェクトに入れて操作したいことがあります。
今回はReflection等を使用してDataReaderやDataTableからエンティティオブジェクトに入れ替えるサンプルについて記載します。
また、DataAdapterを使用してデータベースのデータを更新できるように、エンティティオブジェクトからDataTableへの入れ替えのサンプルも合わせて記載しておきます。

データからエンティティクラスのオブジェクトへ

DataReader、DataTableからエンティティオブジェクトへのマッピングは、DataReader、DataTableの列名(フィールド名)と、エンティティクラスのプロパティ名またはフィールド名をもとに行います。
エンティティのプロパティとフィールドはpublicで公開されているものに限定して取得します。

DataReader → Entities

以下に記載のソースコードはDataReaderからエンティティオブジェクトへ、データを設定するDataReaderToEntitiesメソッドです。
メソッドは引数にIDataReader型のオブジェクトを取り、指定された型のエンティティのオブジェクトをIEnumerable型で返します。

上記のメソッドには、型引数にエンティティクラスの型を指定します。
メソッドでは指定された型からReflectionを使用して、publicなプロパティとpublicなフィールドを取得します。
エンティティオブジェクトのコレクション(List<T>)を作成し、DataReader のフィールド名を取得した後、DataReaderをwhileでループして読み込んでいきます。
DataReaderから1レコードずつ読み込みながら、取得したプロパティとフィールドをforeachでループしてDataReaderのフィールド名と一致するものがあるかを検査し、一致していれば値を取得してエンティティオブジェクトのプロパティまたはフィールドに設定しています。
whileのループでは、プロパティとフィールドの全ての値を設定した後、DataReaderの1レコードに対応するエンティティオブジェクトをエンティティオブジェクトのコレクションに追加しています。

53行目で値を取得する際にConvertToというメソッドを呼んでいますが、これは独自に作成したオブジェクトをコンバートするメソッドです。

以下にソースコードを記載します。

オブジェクトのコンバート

DataReader、DataTableの持つ列のデータ型がエンティティクラスのプロパティ、フィールドと一致していれば問題ないですが、念のためコンバートするメソッドを作成して、値を変換できるなら変換して処理します。また、値がDBNullの場合はnullに変換する処理もこのメソッドで行います。

上記のメソッドはDBNullの場合にnullを返すので、エンティティクラスのプロパティがintやdecimal、DateTimeなどのNull許容値型になっていない場合はデータを入れることができませんので注意してください。

DataTable → Entities

以下のソースコードはDataTableからエンティティオブジェクトへ、データを設定するDataTableToEntitiesメソッドです。

DataTableとエンティティオブジェクトのデータのマッピングもDataReaderの場合とほぼ同様の処理になります。
DataReaderのデータを設定する際はwhileでDataReaderを読み込んでいましたが、DataTableではRowsプロパティをforeachでDataRowを取得してエンティティに設定します。

Entities → DataTable

上記でDataTableからエンティティにデータを設定しましたが、ここではその逆にエンティティからDataTableにデータを設定するメソッド例を記載します。

上記のメソッドはエンティティクラスのプロパティとフィールド情報をもとに、DataTableの列(DataColumn)を作成してデータを設定していきます。
DataTableからエンティティオブジェクトにデータを設定する場合とは逆に、foreachでループしながらエンティティオブジェクトのコレクションを1レコードずつ読み込んでいきます。
foreachでループでは、DataTable行(DataRow)を作成します。
そして、プロパティとフィールドの名前をもとにDataTableの列(DataColumn)を作成し、DataTableの行に値を設定していきます。
すべてのプロパティとフィールドを処理した後、DataTableに行を追加します。

使用例

使用例としてSQLServer簡単なテーブルを作成してデータを取得し、取得したデータをエンティティオブジェクトへ設定する例と、エンティティオブジェクトからDataTableへデータを設定する例を記載しておきます。

使用するテーブル

データを取得するテーブルとしてCustomerというテーブルを作成します。データベースはTestDatabaseという名前のデータベースがすでに作成済みであることとします。

Customer(顧客)テーブル定義

列論理名 列物理名 データ型 備考
顧客ID CustomerId int PrimaryKey
氏名(姓) LastName varchar (50)
氏名(名) FirstName varchar (50)
登録日時 RegisterDate datetime
CREATE

INSERT

エンティティクラス

エンティティクラスは以下のように定義します。
プロパティ名はテーブルの列名を同じにします。

エンティティクラスは、顧客ID(CustomerId)、氏名(姓)(LastName)、氏名(名)(FirstName)はプロパティとして作成しています。登録日時(RegisterDate)のみフィールドとして作成しています。

Windowsフォームアプリケーションのプロジェクトを作成して、以下のようなDataGridViewを3つ並べ、ボタンを配置したフォームを作成します。

データとエンティティのマッピングサンプル画面

フォームのソースに上記のメソッドDataReaderToEntitiesメソッド、ConvertToメソッド、DataTableToEntitiesメソッド、EntitiesToDataTableメソッドのソースコードを実装します。
そして画面に配置したボタンのクリックイベントに、以下のソースコードを実装します。

ここまで実装が終わったら、ビルドして実行(F5でデバッグ実行)します。

フォームが表示されたら、左下のボタン(button1)をクリックします。

データとエンティティのマッピングサンプル画面実行結果

上記のようにDataReaderからエンティティ、DataTableからエンティティ、エンティティからDataTableへデータを設定した結果がグリッドに表示されました。

今回はDataReaderやDataTableからエンティティオブジェクトに、データをマッピングして設定する実装例をご紹介しました。
システムのリプレースなどで、旧システムでDataTableやDataSetにデータを取得するライブラリがすでに実装されている場合には使えるかもしれません。
Entity FrameworkDapperなどのO/Rマッパーで実装しなおすことは、とても手間のかかる作業です。
最近では昔ほどシステムのリプレースに大きな予算を割いてくれるクライアントは多くありません。少しでも工数を減らしてシステムのリプレースを行うための旧資産の活用方法としては、今回のサンプルは使えるのではないかと思います。