特集

ASP.NETで実践するO/Rマッピング(iBATIS.NET編)

山田 祥寛(http://www.wings.msn.to/
2005/10/08
Page1 Page2 Page3


 前回では、O/RマッピングおよびO/Rマッピング・ツールの概要について解説し、.NET向けの代表的なO/Rマッピング・ツールである「NHibernate」を紹介した。

 O/Rマッピング・ツールを使えば、(C#やVB.NETの)オブジェクトとデータベース上のテーブルとをマッピングできる。これによって、アプリケーションからはオブジェクトのプロパティにアクセスするだけで、直感的にテーブル上の各フィールドにアクセスすることが可能になるというわけだ。

 前回の冒頭で示しているように、.NET環境で利用可能なO/Rマッピング・ツールはすでにいくつもが提供されている。今回は、NHibernateと並び.NET向けの代表的なO/Rマッピング・ツールである「iBATIS.NET」について解説しながら、実際にそれを利用したASP.NETのWebアプリケーションを作成していく。

iBATIS.NET

 前回で見たように、NHibernateはSQLクエリを自動生成するため、アプリケーションがバックエンドのデータベースに依存しにくい、そもそも開発者がSQLを意識しなくてよい、などのメリットがある。

 しかしその半面で、SQLクエリによる開発に精通した開発者にとっては、コードが冗長になりやすい、細かなパフォーマンス・チューニングが行いにくい、などのデメリットがあるのも事実だ。もしもそのようなデメリットをメリット以上に強く感じているならば、iBATIS.NETという選択肢を検討してもよいだろう。

 iBATIS.NETはApache Foundationから提供されているオープンソースのO/Rマッピング・フレームワークである*。このiBATIS.NETがNHibernateと大きく異なるのは、SQLクエリを開発者自身が記述するタイプのO/Rマッピング・ツールであるという点だ。

 iBATIS.NETでは、SQLクエリを外部ファイル化するだけなので、NHibernateなどに比べると手軽に利用できる、細かなパフォーマンス・チューニングも直感的に行いやすい、コードからSQLクエリを分離するのでコードの見通しがよくなる、などのメリットがある。もちろん、半面でSQLを意識しなければならない、使用しているSQL文によってはバックエンドのデータベース製品に依存する可能性がある、などのデメリットもあるわけだが、両者のメリット/デメリットを理解して、うまく使い分けていただきたい。

 それではさっそく、iBATIS.NETを利用したデータベース・アクセスの手順を見ていくことにしよう。

* iBATIS.NETは、正確にはO/Rマッピング機能をつかさどる「SQL Maps」とDI(Dependency Injection)機能をつかさどる「DAO Framework」という2つの機能から構成されるフレームワーク(ライブラリ)だ。本稿では、このiBATIS.NETのSQL Maps機能についてのみ言及するものとし、以降も何の前置きもなく、iBATIS.NETといった場合にはSQL Mapsを指すものとする。iBATIS DAO Frameworkに関する詳細を知りたい方は、「iBATIS.NETにてO/Rマッピングを行う(DAO Framework編)」が参考になる。

iBATIS.NETのインストールと環境設定

 前回のNHibernate同様、iBATIS.NETを利用するには、あらかじめ必要なファイルの配置と設定ファイルの定義を済ませておく必要がある。具体的なサンプルWebアプリケーションを見ていく前に、まずはiBATIS.NETの動作に必要な環境設定を済ませておこう。

[1]iBATIS.NETの利用に必要なファイルを配置する

 iBATIS.NETを利用するに当たっては、まず以下のサイトから必要なファイルをダウンロードする必要がある。本稿では、執筆時点での最新バージョンである1.2.1を例に取り上げるが、iBATIS.NETは日々精力的に更新が行われている。その時々の最新安定版を利用していただきたい。

 ダウンロードしたファイル(本稿の例では、DataMapper-bin-1.2.1.zip)を解凍すると、いくつかのファイルが展開されるはずだ。ここでは、ダウンロード・ファイルに含まれるすべての「.dll」ファイルを、アプリケーション・ルート直下の「bin」フォルダにコピーする。

 また、providers.configをアプリケーション・ルートの直下にコピーしておこう。providers.configは、iBATIS.NETが利用する接続プロバイダ(個々のデータベース製品にアクセスするための基本的なライブラリ群)の設定を定義する設定ファイルだ。

[2]iBATIS.NETのデータベース接続情報を定義する

 iBATIS.NETでは、まずデータベース接続情報を専用の設定ファイルであるsqlMap.configで宣言しておく必要がある。以下は、本稿のサンプルで利用するsqlMap.configの記述例だ。

 なお、sqlMap.configは一から自分で記述しても構わないが、ダウンロード・ファイルの中にもテンプレートとしてSqlMap-sample.configが含まれている。これには最低限必要な記述が含まれているので、これを編集すればタイプミスも少なく、効率的に作業を進められるはずだ。

<?xml version="1.0" encoding="UTF-8" ?>

<sqlMapConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="SqlMapConfig.xsd">

  <providers resource="providers.config" />

  <database>
    <provider name="sqlServer1.1"/>
    <dataSource name="sample" connectionString="Data Source=(local);User ID=sa;Password=sa;Persist Security Info=True;Initial Catalog=sample" />
  </database>

  <sqlMaps>
    <sqlMap resource="./Book.xml" />
  </sqlMaps>

</sqlMapConfig>
iBATIS.NETが使用するデータベース接続情報の設定例(sqlMap.config)

 作成したsqlMap.configは、ほかの「.aspx」ファイルと同じフォルダ(本稿の場合ではアプリケーション・ルートの直下)に保存すること。

 <providers>要素には、接続プロバイダの情報を定義した設定ファイル(providers.config)へのパスを指定する。先述したようにproviders.configはiBATIS.NETが対応している接続プロバイダを記述した設定ファイルだ。providers.configはあらかじめダウンロード・ファイルに含まれているので、これをコピーするだけでよく、自分で編集する必要はない。

 以下に、providers.configで定義されている主な接続プロバイダを挙げておく。

接続プロバイダ名 データベース
sqlServer1.0 SQL Server 7.0/2000(.NET Framework 1.0用)
sqlServer1.1 SQL Server 7.0/2000(.NET Framework 1.1用)
OleDb1.1 OLE DB(.NET Framework 1.1用)
Odbc1.1 ODBC(.NET Framework 1.1用)
oracle9.2 Oracle 9.2
oracle10.1 Oracle 10.1
oracleClient1.0 Oracle(Microsoftから提供されているもの)
MySql MySQL
SQLite3 SQLite 3.0
Firebird1.7 FireBird
PostgreSql0.7 PostgreSQL
iDb2.10 IBM DB2
iBATIS.NETが対応する接続プロバイダ

 ただし、SQL Server、OLE DB、ODBC以外のデータベースを利用する場合には、別途、データベース専用の接続プロバイダ(.NETデータ・プロバイダ)が必要になるので、注意してほしい。

 実際の接続設定を行うのは、<database>要素の役割だ。使用する接続プロバイダを<provider>要素で、接続文字列を<dataSource>要素で、それぞれ定義する。

 <sqlMaps>要素では、iBATIS.NETで使用するマッピング・ファイル(後述)へのパスを指定する。マッピング・ファイルとは、NHibernateの解説でも紹介したとおり、テーブル上のフィールド(列)とクラスのプロパティとを関連付けるための定義ファイルのことだ。ここでは、マッピング・ファイルとしてBook.xmlを指定する。

[3]マッピング・ファイルを定義する

 次に、sqlMap.configで指定したマッピング・ファイルBook.xmlを定義し、booksテーブルとBookクラスとを関連付けておこう。なお、booksテーブル、Bookクラスはいずれも前回のNHibernate編で使用したものをそのまま利用するものとする。

<?xml version="1.0" encoding="UTF-8" ?>

<sqlMap namespace="Book"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="SqlMap.xsd">

  <alias>
    <typeAlias alias="Book" type="Com.Msn.Wings.Book, Book" />
  </alias>

  <resultMaps>
    <resultMap id="booksResult" class="Book">
      <result property="Isbn" column="isbn" />
      <result property="Title" column="title" />
      <result property="Price" column="price" />
      <result property="Publish" column="publish" />
      <result property="Published" column="published" />
    </resultMap>
  </resultMaps>

  <statements>

    <select id="getBooksInfo" resultMap="booksResult">
      SELECT isbn,title,price,publish,published FROM books WHERE publish=#value#
    </select>

      ……中略……

    <insert id="setBookInfo" parameterClass="Book">
      INSERT INTO books(isbn,title,price,publish,published) VALUES(#Isbn#,#Title#,#Price#,#Publish#,#Published#)
    </insert>

  </statements>

</sqlMap>
iBATIS.NETによるマッピング・ファイルの記述例(Book.xml)

 クラスとテーブルとの関連付けを行うのは、<resultMap>要素の役割だ。id属性にマッピング名を、class属性に関連付けるクラス名を指定する。なお、クラス名はあらかじめ<typeAlias>要素で宣言したエイリアス(別名)と対応している必要がある。<typeAlias>要素の構文は以下のとおりだ。

<typeAlias alias="エイリアス名" type="クラスの完全修飾名, アセンブリ名" />

 <resultMap>要素配下の<result>要素は、個々のフィールド名とプロパティを関連付ける。property属性にはクラスのプロパティ名を、column属性には対応するフィールド名をそれぞれ指定する。

 次の<statements>要素は、iBATIS.NETから発行するSQLクエリを管理する。<statements>要素の配下には、以下の表で示すような要素と属性とを記述することができる。

要素 属性 概要
<insert>
<update>
<delete>
id SQLクエリ名
parameterClass SQLクエリ内のプレイスホルダに値を設定するためのクラス名
parameterMap SQLクエリ内のプレイスホルダに値を設定するためのマップ名
<select> id SQLクエリ名
parameterClass SQLクエリ内のプレイスホルダに値を設定するためのクラス名
parameterMap SQLクエリ内のプレイスホルダに値を設定するためのマップ名
resultClass 取得した結果セットをセットするクラス名
resultMap 取得した結果セットをセットするマップ名
<statements>要素配下で指定可能な主な子要素と属性

 まず<select>要素は、名前からも容易に推測できるように、SELECT命令を発行する際に利用される。INSERT/UPDATE/DELETEの各命令を発行する場合には、それぞれ対応する要素で指定すればよい。

 id属性は、SQLクエリを一意に特定するための論理名だ。コード中からマッピング・ファイルを検索する際のキーとなる情報なので、マッピング・ファイル内で必ず一意になるように指定する必要がある。

 resultMap属性は、データベースから取得した結果セットを永続化クラス(永続化クラスについては前回の「[4]永続化クラスを定義する」の項を参照)にマッピングするためのマップ名を指定する。先ほど<resultMap>要素で指定したid属性の値をセットすること。

 発行するSQLクエリ本体は、<select>(または<insert>/<update>/<delete>)要素の本体に記述する。本稿の冒頭でも記述したように、iBATIS.NETではNHibernateのようなO/Rマッピング・ツールとは異なり、SQLクエリを開発者が明示的に記述する必要がある。

 例えば以下の<select>要素は、プログラム・コードから「getBooksInfo」というIDで識別され、2行目にあるSELECT命令をデータベースに対し実行する。

<select id="getBooksInfo" resultMap="booksResult">
  SELECT isbn,title,price,publish,published FROM books WHERE publish=#value#
</select>

 そしてマッピング・ファイル内の以下のような<resultMap>要素の記述に従って、検索結果の各フィールド値がBookオブジェクトの各プロパティに代入されるというわけだ。

<resultMap id="booksResult" class="Book">
  <result property="Isbn" column="isbn" />
  <result property="Title" column="title" />
  <result property="Price" column="price" />
  <result property="Publish" column="publish" />
  <result property="Published" column="published" />
</resultMap>

 SQLクエリには、「#value#」(無名パラメータ)、または「#パラメータ名#」(名前付きパラメータ)の形式でプレイスホルダを設置することが可能だ。

 無名パラメータは、コード中からも名前などを意識することなく、直接に値をセットできるのがポイントだ。クエリ内にプレイスホルダが1つしかない場合には、無名パラメータを利用することでコードをシンプルに記述できる。

 一方、クエリ内にプレイスホルダが複数存在する場合には、名前付きパラメータを利用するとよい。詳細は後述するが、名前付きパラメータを利用することで、parameterClass属性で指定されたクラスの同名のプロパティ値が自動的にセットされる。つまり、上記のマッピング・ファイルの例(INSERT命令)であれば、Book.Isbnプロパティの値が#Isbn#パラメータに、Book.Titleプロパティの値が#Title#パラメータに、それぞれ自動的にSQLクエリに割り当てられるというわけだ。


 INDEX
  [特集] ASP.NETで実践するO/Rマッピング(iBATIS.NET編)
  1.iBATIS.NETのインストールと環境設定
    2. iBATIS.NET経由でデータベースを検索する
    3. iBATIS.NETによるデータ登録
 


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

Insider.NET 記事ランキング

本日 月間
ソリューションFLASH