Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

NHibernateを利用してSQLを書かずにデータベースにアクセスする方法

NHibernateでO/Rマッピングを行う

  • LINEで送る
  • このエントリーをはてなブックマークに追加

本稿では、「NHibernate」というオープンソースのプロダクトについて紹介します。NHibernateは、SQLを書かずにテーブルのデータとクラスをシームレスに変換させるO/Rマッピングを実現するため、コーディングの量を軽減することができます。

はじめに

 データベースにアクセスするアプリケーションの開発で、個々のテーブルに対してSQLを書く作業が繰り返しで冗長だと感じたことはありませんでしょうか。本稿では、このような問題の解決に有効な「NHibernate」というオープンソースのプロダクトについて紹介します。NHibernateは、SQLを書かなくともテーブルのデータとクラスをシームレスに変換させるO/Rマッピング(Object/Relational Mapping)を実現できるため、コーディングの量を軽減することが可能になります。

対象読者

 .NETにて開発を行っている方を対象としています。

必要な環境

 サンプルはVisual Studio .NET 2003で作成され、.NET Framework 1.1、NHibernate 0.91で動作確認をしています。

NHibernateの概要と入手方法

 NHibernateはO/Rマッピングを行うオープンソースのライブラリです。NHibernateは、軽快な動作と使い勝手の良さから人気が上がっているJavaの「Hibernate」を.NETへ移植したものです。NHibernateは、別稿でご紹介したiBATIS.NETと異なり、SQLを書かなくともデータの取得や更新を行うことができます。またHQL(Hibernate Query Language)と呼ばれるSQLに似た独自のオブジェクトクエリ言語によって、集計関数やサブクエリをサポートするなどと、柔軟性が高いことが特徴です。

 NHibernateを入手するにはWebサイトの「Download NHibernate」のリンクからダウンロードしてください。なお執筆時点での最新バージョンは0.91です。

NHibernateの設定

 Visual Studioから使用する場合、ソリューションエクスプローラの[参照設定]を右クリックして、[参照の追加]から「NHibernate.dll」を選択します。NHibernateは、

 といった他のライブラリを使用しますので、これらのファイルを「NHibernate.dll」と同じフォルダに配置するようにしてください。

サンプルアプリケーションについて

 サンプルは、書籍マスタのメンテナンスを行うWindowsアプリケーションです。[デバッグ]メニューの[開始]にて画面が起動します。

書籍マスタのメンテナンス画面
書籍マスタのメンテナンス画面

 このサンプルは、MDB(Microsoft Accessのデータベース形式)にアクセスし、データの追加・更新・参照・削除を行います。なお「NHibernate.dll(nhibernate-0.9.1.0.zip)」が同梱されているため、改めてNHibernateを入手する必要はありません。

 このサンプルに登場する主要なクラス・テーブル・設定ファイルは下図の通りです。

NHibernateの主要クラス・設定ファイル
NHibernateの主要クラス・設定ファイル

サンプルのテーブルレイアウト

 書籍マスタ(BOOK)のレイアウトは以下の通りです。

書籍(BOOK)マスタ
列名桁数説明
ISBN文字列型10図書コード(主キー)
TITLE文字列型50書籍名
SALE_DATE日付時刻型8発売日
PRICE数値型8価格
AUTHOR_ID数値型8著者コード

 著者(AUTHOR)マスタのレイアウトは以下の通りです。

著者(AUTHOR)マスタ
列名桁数説明
ID数値型8著者コード(主キー)
NAMEテキスト型50著者名
TELテキスト型15電話番号
REG_DATE日付時刻型8登録日

 書籍マスタのAUTHOR_IDカラムには、著者マスタの「ID」が設定されています。

「NHibernate」のマッピング準備

 NHibernateを動作させるためには、以下の手順で実装を行います。

  1. マッピング対象クラスの作成
  2. GetterとSetterから構成されるシンプルなクラスを作成します。
    本稿ではBookクラスとAuthorクラスを作成します。
  3. マッピングファイル(「*.hbm.xml」)の作成
  4. テーブルとクラス間のマッピング設定を行います。
    本稿では「Book.hbm.xml」と「Author.hbm.xml」を作成します。
  5. アプリケーション構成ファイルの記述
  6. 「App.config」(Web.config)にデータベースの接続情報(種類、ユーザなど)を定義します。

マッピング対象クラス「Book.cs」の作成

 まず「BOOK」テーブルのデータを格納するBookクラスを作成します。Bookクラスは「BOOK」テーブルと同じ属性を持つシンプルなクラスです。

「Book.cs」
public class Book
{
  private string _Isbn;
  private string _Title;
  private DateTime _SaleDate;
  private int _Price;
  private Author _Author;

  public string Isbn 
  {
    get{ return _Isbn; }
    set{_Isbn = value; }
  }
  
  //(以下同様にget/set設定)

}

 「BOOK」テーブルから読み込まれたデータがBookクラスにセットされ、Bookクラスのプロパティの値が「BOOK」テーブルに反映されます。(Bookクラスと同様にAuthorクラスも作成します。)

「Book.hbm.xml」にマッピング定義を記述

 「Book.hbm.xml(クラス名+.hbm.xml)」というファイルを作成し、クラスとテーブルの関係(マッピング)を定義します。

「Book.hbm.xml」
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">

  <class name="NHibernateSample.Domain.Books.Book, NHibernateSample" 
    table="BOOK">
    <id name="Isbn">
      <generator class="assigned" />
    </id>
    <property name="Title" />
    <property name="Price" />
    <property name="SaleDate" column="SALE_DATE" />
    <many-to-one name="Author" column="AUTHOR_ID" />
  </class>
  
</hibernate-mapping>

対象クラスとテーブルの紐づけ

 「<class name="クラス名, アセンブリ名" table="テーブル名" />」という形式でマッピングするクラスとテーブルを定義します。このサンプルでは、NHibernateSample.Domain.Books.Bookクラスと「BOOK」テーブルを紐づけています。

プロパティとカラムのマッピング

 「<property name="プロパティ名" column="カラム名" />」という形式で、クラスのプロパティとテーブルのカラムのマッピングを定義します。このサンプルでは、『「BOOK」テーブルのSALE_DATEカラム』と『bookクラスのSaleDateプロパティ』を紐づけています。なおTitlePriceのようにプロパティ名とカラム名が同じ場合、カラム名は省略できます。

主キー列の定義

 主キー列Isbnの定義を行います。設定方法は「property」と同じです。ただし、主キー値の生成方法を「<generator class="IDジェネレーター名" />」という子要素にて指定する必要があります。サンプルアプリケーションでは、プログラムから値を設定するため「assigned(アプリケーションでIDを生成する方式)」としています。なお、他のIDジェネレータの例としては、

  • incrementlong, short, int型の数値をインクリメンタルに生成)」
  • identity(SQLServerやMySQLのidentity列の使用)」
  • sequence(OracleやPostgreSQLのsequenceの利用)」
  • hilo(hi/loアルゴリズムによるID生成)」
  • uuid.hex(128ビットUUIDアルゴリズムによるID生成)」

 などがありますので状況に応じて使い分けてください。

関連の設定

 BookクラスのプロパティがAuthorクラスであるため、これらの関連を設定します。サンプルのようにトランザクションデータからマスタを参照するような関連は「N対1の関係」と呼び、「<many-to-one name="プロパティ名" column="カラム名" />」という形式で定義します。この設定によりBookクラスの読み込み時に、対応するAuthorクラスも読み込まれるようになります。

 なおNHibernateは「1対Nの関係(プロパティにコレクションを持つような場合)」や「1対1の関係(テーブル分割など同じキーを持つ場合)」といった関連もサポートしています。

注意
 Visual Studioで開発する場合、マッピング定義ファイル「*.hbm.xml」のビルドアクションは「埋め込まれたリソース」に設定してください。この設定によりアセンブリに「*.hbm.xml」が埋め込まれ、NHibernateからマッピング定義を読み込めるようになります。そのため、クラスを変更せずに「*.hbm.xml」だけを更新した場合は「ビルド」ではなく、必ず「リビルド」を実行するようにしてください。ビルドでは更新した内容がアプリケーションに反映されませんので注意が必要です。

 マッピングファイルの設定の詳細については、NHibernate documentation Chapter 3もしくはHibernateの日本語訳 第5章が参考になるでしょう。

アプリケーション構成ファイルにデータベース情報を記述

 アプリケーション構成ファイル「App.config」(ASP.NETの場合は「Web.config」)に、データベースの接続先に関する設定を行います。

「App.config」(一部抜粋)
<configSections>
  <section name="nhibernate" 
    type="System.Configuration.NameValueSectionHandler, System, 
    Version=1.0.5000.0,Culture=neutral, 
    PublicKeyToken=b77a5c561934e089" />
</configSections>

<nhibernate>

  <add key="hibernate.show_sql" value="true" />

  <add key="hibernate.connection.provider"
    value="NHibernate.Connection.DriverConnectionProvider" />

  <add key="hibernate.connection.driver_class"
    value="NHibernate.Driver.OleDbDriver" />

  <add key="hibernate.dialect"
    value="NHibernate.Dialect.MsSql7Dialect" />

  <add key="hibernate.connection.connection_string"
    value="Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;
    Data Source=./NHibernateSample.mdb" />
    
</nhibernate>

 NHibernateは執筆時点で下表のデータベースに対応していますので、接続先に応じて「driver_class(使用するDriverクラスを設定)」「dialect(使用するDialectを設定)」「connection_string(データベースの接続文字列を設定)」を設定します。

データベース使用Driver使用Dialectconnection_string例
DB2 UDBDB2DriverDB2DialectDSN=SampleDb;UID=admin;PWD=pass
FirebirdFirebirdDriverFirebirdDialectDatabase=C:\DB\SampleDb.GDB;
User=admin;Password=pass;Dialect=3;
Server=localhost
Microsoft AccessOleDbDriverMsSql7DialectProvider=Microsoft.Jet.OLEDB.4.0;
User ID=admin;
Data Source=./NHibernateSample.mdb
MySQLMySqlDataDriverMySQLDialectServer=server;Database=SampleDb;
User ID=admin;Password=pass
OracleOracleClientDriver(OracleDataClientDriver)OracleDialect(Oracle9Dialect)Data Source=SampleDb;User ID=admin;Password=pass;
PostgreSQLNpgsqlDriverPostgreSQLDialectServer=localhost;Database=SampleDb;
User ID=admin;Password=pass;
Encoding=UNICODE
SQL Server(MSDE)SqlClientDriverMsSql7Dialect(MsSql2000Dialect)Server=localhost;database=SampleDb;
Password=pass;User ID=admin
SQLiteSQLiteDriverSQLiteDialectData Source=%APPDATA%\Aample\Data.sqlite.db;
New=False;UTF8Encoding=True;
Version=3

 接続するデータベースの詳細設定については、NHibernate FAQを参考にすると良いでしょう。

「NHibernate」でデータを操作する

 ここまでの手順でO/Rマッピングの準備は完了です。それでは、テーブルのデータを操作してみましょう。

NHibernateによるデータベース接続

 まず、データベースに接続するため、ConfigurationクラスとISessionFactoryインターフェースを使用して、アセンブリの登録とISessionの取得を行っています。

NHibernateの接続処理
//NHibernateの接続設定
Configuration cfg = new Configuration();
//アセンブリの登録
cfg.AddAssembly("NHibernateSample");
ISessionFactory factory = cfg.BuildSessionFactory();
//セッションの取得
ISession session = factory.OpenSession();

 NHibernateが提供する主要クラスを下表に整理しておきます。

NHibernateの主要クラス
クラス・インタフェース名役割
NHibernate.Cfg.Configurationマッピングファイルの読み込みとISessionFactoryの生成を行うクラス。
NHibernate.ISessionFactoryISessionの生成を行うインターフェース。
NHibernate.ISessionデータベース操作に関する中心的なインターフェース。
NHibernate.ITransactionトランザクションを管理する。ISession.BeginTransaction()によって生成されるインターフェース。

データの挿入(INSERT)

 ISession#BeginTransactionを使用してトランザクションを開始した後、Bookインスタンスを生成し値を設定します。

INSERTの例
//トランザクションの開始
ITransaction transction = session.BeginTransaction();
//オブジェクトに値をセット
Book book = new Book();
book.Isbn = "4987654321"; 
book.Title = "NHibernate入門"; 
book.Price = 4500;
book.SaleDate = new DateTime(2005,8,1);
book.Author.Id = 3;
session.Save(book);
//書き込み(トランザクションをコミット)
transction.Commit();
session.Close();

 テーブルにデータを挿入(INSERT)するにはISession#Saveを使用します。トランザクションをコミット(ITransaction#Commit)し、セッションを閉じることで一連の処理は完了となります。

データの取得・更新・削除(SELECT・UPDATE・DELETE)

 続けてデータの取得・更新・削除を行います。

 1件のデータを読み出す(SELECT)にはISession#Loadを使用します。Loadメソッドの引数には、読み出すクラスの型「typeof(Book)」と検索するキーの値を指定します。

1件SELECTとUPDATEの例
//ISBNが「4900003428」のBookデータを読み込み
Book book = (Book)session.Load(typeof(Book), "4900003428");
//タイトルを変更
book.Title = "C#入門(改訂3版)";
//データを更新
session.Update(book);

 更新(UPDATE)するには、更新したいプロパティに値を設定した後でISession#Updateを使用します。

DELETEの例
session.Delete(book)

 削除(DELETE)するには、bookクラスにキー項目を設定した後でISession#Deleteを使用します。

「NHibernate」で複数のデータを取得する

 実際の開発案件では、データを1件表示するだけではなく、複数件表示する場合も多いのではないでしょうか。ここでは複数件のデータをコレクションに格納する2つの方法(「Criteria」と「HQL」)を紹介します。

Criteriaによるデータの取得

 ISession#CreateCriteriaを使用することで複数件のデータを読み出すことができます。引数には、読み出すクラスの型を指定します。

複数件取得の例(Criteria全件)
//BOOKテーブルの全件取得
IList books = session.CreateCriteria(typeof(Book)).List();
//結果を出力
foreach (Book book in books)
{
  Console.WriteLine(book.Title);
}

 上の例では、「BOOK」テーブルの全レコードが読み出されます。もし条件を付加したい場合にはExpressionクラスを使用します。

複数件取得の例(Criteria条件付き)
//価格(Price)が3000円以上(Greater than or Equal)のデータを抽出する場合
IList books = session.CreateCriteria(typeof(Book)).
  Add(Expression.Ge("Price",3000)).List();

//価格(Price)が2000円未満(Less Than)のデータを抽出する場合
IList books = session.CreateCriteria(typeof(Book)).
  Add(Expression.Lt("Price",2000)).List();

 この例では3000円以上や2000円未満というような条件を付加しましたが、Expressionクラスには「Eq」「In」「IsNull」「Like」といったメソッドもありますので、必要に応じて条件を変更すると良いでしょう。

HQLによるデータの取得

 Criteriaは便利ですが、複雑な条件でデータを抽出したい場合には、HQLを使用したほうが良いでしょう。HQLは「Hibernate Query Language」と呼ばれるSQLに似たHibernate独自のオブジェクトクエリー言語です。HQLにてデータを読み出すにはISession#Findを使用します。

複数件取得の例(HQL)
//タイトルの入門という文字が含まれるデータを抽出
string hql = 
  "from Book b where b.Title like '%入門%' order by b.Title";
IList books = session.Find(hql);

 この例ではFindメソッドの引数にHQL形式でLIKE句を記述して検索を行っています。HQLの詳細についてはHibernateの日本語訳 第11章が参考になるでしょう。

Tips(マッピングファイルのインテリセンス)

 NHibernateではマッピングファイルの編集作業が多く発生します。開発効率を上げるために、Visual Studioでマッピングファイル「*.hbm.xml」のインテリセンス(補完機能)を効かせることができます。

XMLファイルのインテリセンス
XMLファイルのインテリセンス
  1. XMLスキーマの設定ファイル「nhibernate-mapping-2.0.xsd」を「<VisualStudioのインストールフォルダ>\Common7\Packages\schemas\xml」フォルダにコピーする。
  2. 補完させたいファイル名の拡張子を「*.XML」にする。
  3. XMLファイルの先頭に<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">と記述します。

 この設定によって、[CTRL]+[スペース]キーで要素や属性を表示できるようになります。

まとめ

 NHibernateの特長を整理します。

  • マッピングファイル「*.hbm.xml」にクラスとテーブルの関係を定義します。
  • ISessionの「Save」「Load」「Update」「Delete」メソッドによって、データベースのCRUD(Create、Read、Update、Delete)操作が可能です。
  • ISessionの「CreateCriteria」「Find」メソッドによって、複数データの抽出が可能です。
  • アプリケーション構成ファイルの「driver_class」「dialect」「connection_string」の設定によって、データベースの接続先を変更できるため、特定のデータベースに依存しにくくなります。
  • SQLを記述しないためコーディング量の軽減が期待できます。

 執筆時点でのNHibernateの最新バージョンは0.91ですが、頻繁にバージョンアップが繰り返されているため、正式版が公開される日も近いのではないかと予想されます。興味をもたれた読者はNHibernateを先取りして試してみてはいかがでしょうか。

参考資料

  1. NHibernate(英語)
  2. Hibernateリファレンス・ドキュメント
  3. @IT 『O/Rマッピングの役割とメリット』 山本大 著、2004年4月
  4. オブジェクトの広場 『現場で使えるHibernate』 更谷暢哉 著、2005年7月
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 青木 淳夫 (株式会社ネクストスケープ)(アオキ アツオ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2017年5月時点での登録メンバは52名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂き...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5