8.NHibernate編
これまで、主にRDBMSを対象にしたDBアクセスについて解説を行いましたが、NHibernateはRDBMSではありません。NHibernateはオブジェクト関係(O/R)マッピングフレームワークと言われるもので、言い換えれば、NHibernateを経由したDBアクセスについて解説を行う、ということになります。
Wikipediaでは、オブジェクト関係マッピングについて
データベースとオブジェクト指向プログラミング言語の間の非互換なデータを変換するプログラミング技法である。と解説しています。もう少し簡単に言うとしたら、RDBへのアクセスをあたかもdb4oのようなODBへのアクセスのように行う方法、でしょうか。
NHibernateではマッピング先のRDB上のテーブルへのデータ登録を次の様なコードで実現しています。
Configuration cfg = new Configuration();
cfg.Configure();
ISessionFactory factory = cfg.BuildSessionFactory();
ISession session = factory.OpenSession();
Product product = new Product{ Id = 1, Name = "Clamp", Price = 12.48M, Description = "Workbench clamp" };
session.Save(product);
また、登録したデータの検索はvar result = session.Get<Product>(1);で可能です。
NHibernateは複数のRDBMSをサポートし、これまでの記事で使用したすべてのRDBMSで使用可能です。本稿では、NHibernateを使用した、RDBMSへのDBアクセスについて解説を行います。NHibernateについてはWikipediaなどを参照して下さい。
セットアップ
NHibernateの動作に必要なアセンブリの導入を行います。各RDBMSのセットアップについては、これまでの記事を参照して下さい。ただ、本稿での動作環境は、以前と異なる部分があるので、セットアップ上の変更点については、「おまけ」の節で解説します。アセンブリの導入
NHibernateはSourceForgeのNHibernateプロジェクトページからダウンロード可能です。現時点(2009.09.02)の最新版は2.1.0.GAです(NHibernate 2.1.0はHibernate 3.2.6に相当)。「NHibernate-2.1.0.GA-bin.zip」を任意のディレクトリで展開し、次のアセンブリをGACへインストールまたは環境変数MONO_PATHに設定されているディレクトリへコピーします。
[必要なアセンブリ]
| アセンブリ | 概要 |
|---|---|
| NHibernate.dll | NHibernate Service Provider |
| Iesi.Collections.dll | required from NHibernate |
| log4net.dll | required from NHibernate |
| NHibernate.ByteCode.LinFu.dl | need for proxyfactory.factory_class |
| LinFu.DynamicProxy.dll | need for proxyfactory.factory_class |
[導入例(MONO_PATH)]
$ echo $MONO_PATH
/home/sta/lib
$ unzip NHibernate-2.1.0.GA-bin.zip -d NHibernate-2.1.0.GA-bin/
$ cd NHibernate-2.1.0.GA-bin/Required_Bins
$ cp *.dll ~/lib
$ cd ../Required_For_LazyLoading/LinFu
$ cp *.dll ~/lib
/home/sta/lib
$ unzip NHibernate-2.1.0.GA-bin.zip -d NHibernate-2.1.0.GA-bin/
$ cd NHibernate-2.1.0.GA-bin/Required_Bins
$ cp *.dll ~/lib
$ cd ../Required_For_LazyLoading/LinFu
$ cp *.dll ~/lib
コンフィグファイル
RDBMSへの接続情報等を設定します。「NHibernate-2.1.0.GA-bin.zip」には、各RDBMS用NHibernateコンフィグファイルのテンプレートが含まれています(「展開先/Configuration_Templates」配下)。それらを参考にして、各RDBMS用のコンフィグファイルを用意します(以下は、SQLiteを対象にした設定例になります)。作業する上でのディレクトリ構造は、下表の通りとします。
| ディレクトリ | ファイル |
|---|---|
| ~/src/cs/NHibernateExample/Driver | MonoDataSqliteDriver.cs |
| ~/src/cs/NHibernateExample/Test | SQLite.cfg.xml |
[NHibernateコンフィグファイル例(SQLite.cfg.xml:SQLite用)]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="NHibernateExample">
<property name="connection.driver_class">NHibernateExample.Driver.MonoDataSqliteDriver, NHibernateExample</property>
<property name="connection.connection_string">Data Source=/home/sta/data/sqlite/TestData.db</property>
<property name="show_sql">false</property>
<property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
<property name="query.substitutions">true=1;false=0</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<mapping file="Product.hbm.xml" />
</session-factory>
</hibernate-configuration>
コンフィグファイルの読み込みは、Configuration cfg = new Configuration(); cfg.Configure();とした場合、実行プログラムと同じディレクトリにある「hibernate.cfg.xml」が読み込まれ、
cfg.Configure("SQLite.cfg.xml");
とした場合、同じディレクトリにある任意のファイル「SQLite.cfg.xml」が読み込まれます。SQLite用コンフィグファイルのテンプレートでは、SQLite用データプロバイダを使用するためのドライバとして、「NHibernate.Driver.SQLiteDriver」が設定されていますが、同ドライバで呼び出しているのは「SQLite.NET」であり、Monoで標準提供されている「Mono.Data.Sqlite」ではありません。ということで、次のような「Mono.Data.Sqlite」用のドライバを用意する必要があります。
[Mono.Data.Sqlite用ドライバ(MonoDataSqliteDriver.cs)]
using System;
using NHibernate.Driver;
namespace NHibernateExample.Driver
{
public class MonoDataSqliteDriver : ReflectionBasedDriver
{
public MonoDataSqliteDriver() : base(
"Mono.Data.Sqlite",
"Mono.Data.Sqlite.SqliteConnection",
"Mono.Data.Sqlite.SqliteCommand")
{
}
public override bool UseNamedPrefixInSql
{
get { return true; }
}
public override bool UseNamedPrefixInParameter
{
get { return true; }
}
public override string NamedPrefix
{
get { return "@"; }
}
public override bool SupportsMultipleOpenReaders
{
get { return false; }
}
}
}
また、NHibernateではデータプロバイダの呼び出しにReflection(System.Reflection.Assembly.Load)を使用しており、GACにインストールされているアセンブリを呼び出すために、App.config(foo.exe.config)に次の設定が必要になりますが、<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="Mono.Data.Sqlite"
fullName="Mono.Data.Sqlite, version=2.0.0.0, publicKeyToken=0738eb9f132ed756, culture=neutral" />
</assemblyBinding>
</runtime>
</configuration>
上記設定はMono 2.4上では有効になりませんでした(未対応のようです)。そこで、必要なアセンブリのリンクをMONO_PATHで設定されているディレクトリに作成して、動作確認を行いました。$ cd ~/lib
$ ln -s /opt/mono/2.4/lib/mono/2.0/Mono.Data.Sqlite.dll .
$ ln -s /opt/mono/2.4/lib/mono/2.0/Mono.Data.Sqlite.dll .
マッピング
次のようなProductsテーブルに関連付けられる、Productクラス、NHibernateマッピングファイルを用意します。| ディレクトリ | ファイル |
|---|---|
| ~/src/cs/NHibernateExample | Product.cs |
| ~/src/cs/NHibernateExample/Test | Product.hbm.xml |
[Productsテーブル]
create table Products( ProductID int not null primary key, ProductName text not null, Price numeric null, ProductDescription text null);
[Productクラス(Product.cs)]
namespace NHibernateExample
{
public class Product
{
int _id;
string _name;
decimal? _price;
string _description;
public virtual int Id
{
get { return _id; }
set { _id = value; }
}
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public virtual decimal? Price
{
get { return _price; }
set { _price = value; }
}
public virtual string Description
{
get { return _description; }
set { _description = value; }
}
public override string ToString()
{
return "ID:" + _id + " NAME:" + _name + " PRICE:" + _price + " DESCRIPTION:" + _description;
}
}
}
[NHibernateマッピングファイル(Product.hbm.xml)]
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernateExample"
namespace="NHibernateExample">
<class name="Product" table="Products">
<id name="Id" column="ProductID">
<generator class="assigned" />
</id>
<property name="Name" column="ProductName" not-null="true" />
<property name="Price" column="Price" />
<property name="Description" column="ProductDescription" />
</class>
</hibernate-mapping>
マッピングファイルはNHibernateコンフィグファイル内で指定し、<mapping file="Product.hbm.xml" />Productクラスはライブラリとしてビルドします。
$ gmcs -t:library -r:NHibernate.dll -out:./Test/NHibernateExample.dll Product.cs -recurse:./Driver/*.cs
Monoで他のDBも使ってみたよ!+(db4o、NHibernate編)5 へ続く。


0 件のコメント:
コメントを投稿