2009年8月28日金曜日

Monoで他のDBも使ってみたよ!+(db4o、NHibernate編)1


はじめに

CodeZineMonoで他のDBも使ってみたよ!(Firebird、DB2編)が公開されたけど、元々は
  • 前編: Monoで他のDBも使ってみたよ!+(Firebird、DB2編)
  • 後編: Monoで他のDBも使ってみたよ!+(db4o、NHibernate編)
という形で投稿したものだった。

 後編部分については、残念ながらボツ稿となってしまい、CodeZine で公開されることはないけれど、ある程度まとめたこともあり、何回かに分けて、blog 上で公開することにした。

 「Monoで他のDBも使ってみたよ!(Firebird、DB2編)」と合わせて読んでもらえればありがたい。

 ということで、後編いってみよう!

前編では

前編では、MonoとFirebird、DB2を使用したDBアクセスについて解説を行いました。
引き続き、Monoとdb4o、NHibernateを使用したDBアクセスについて解説します。

6.必要な環境(後編)

以下の環境で動作確認を行いました(VirtualBox 2.2.4を使用しています)。

ホストOS側

  • OS: Ubuntu 9.04 Desktop
  • Mono 2.4
  • db4o 7.4
  • NHibernate 2.1.0.GA
  • Npgsql 2.0.5
  • Connector/Net 6.0.3
  • Firebird .NET Data Provider 2.1.0
  • SQLite3 3.6.10
  • Oracle Database 10g Express Client 10.2.0.1
  • unixODBC 2.2.11
  • IBM Data Server Client - V9.5 Fix Pack 3b for Linux (32 bit, Intel)

ゲストOS側

Ubuntu 9.04 Server

  • OS: Ubuntu 9.04 Server
  • PostgreSQL 8.3.7
  • MySQL 5.1
  • Oracle Database 10g Express Universal Edition 10.2.0.1
  • Firebird 2.1
  • DB2 Express-C 9.5.2

Windows 7 RC

  • OS: Windows 7 RC
  • SQL Server 2008 Express Edition SP1

7.db4o編

今までの記事で扱ってきたDBMSは基本的にはリレーショナルデータベース管理システム(RDBMS)に属するものですが、db4oはオブジェクトデータベース管理システム(ODBMS)と言われるものに属します。つまりオブジェクトデータベースを扱えるわけですが、オブジェクトデータベースとは何でしょうか?Wikipediaでは
オブジェクトデータベースは、オブジェクト指向プログラミングで使うオブジェクトの形式で表現されるデータを格納するデータベースである。
と解説しています。

 具体的にはどういうことなのか。db4oでは、作成したオブジェクト(インスタンス)の格納を次のコードで実現しています。
  1. IObjectContainer db = Db4oFactory.OpenFile("/path/to/dbfile");  
  2. db.Store(new Product(1, "Clamp", 12.48, "Workbench clamp"));  
また、格納されたオブジェクトの検索は、
  1. IObjectSet result = db.QueryByExample(new Product(1, nullnullnull));  
になります。

 これらはdb4oで用意されている、より簡易な手法を使用した例と言えますが、オブジェクトそのものを通してDBアクセスを行えるということはなんとなく分かると思います。

 db4oでは、その機能を実現するのに提供されているのは、いくつかのアセンブリだけで、その他に管理ソフトウェアといったものはありません。また、データベースは1つのファイルとして作成されるので、イメージ的にはSQLiteに近いでしょうか。

 本稿では、そんな軽量なdb4oを使用した基本的なDBアクセスについて解説を行います。db4oについてはdb4objects 日本語ポータルを参照して下さい。

セットアップ

db4oの動作に必要なアセンブリの導入、および動作確認用のdb4o DBの作成を行います。また、「db4o編」においてゲストOS側の資源を使うことはなく、以下の内容はすべてホストOS側で行うものです。

アセンブリの導入

db4o Developer Community - Mono -から、ページ下部の[Mono binaries provided by the community]にある「db4o-7.4.mono.tar.gz」へのリンクを選択し、ダウンロードします。

 「db4o-7.4.mono.tar.gz」を任意のディレクトリで展開し、以下のアセンブリをGACへインストールまたは環境変数MONO_PATHに設定されているディレクトリへコピーします。

[必要なアセンブリ]
アセンブリ概要
Db4objects.Db4o.dlldb4o Engine
Db4objects.Db4o.Linq.dlldb4o LINQ Provider
Mono.Cecil.dllrequired from db4o LINQ Provider
Cecil.FlowAnalysis.dllrequired from db4o LINQ Provider

[導入例(MONO_PATH)]
$ echo $MONO_PATH
/home/sta/lib
$ tar -xvf db4o-7.4.mono.tar.gz
$ cd db4o-7.4/Release
$ cp Db4objects.Db4o.dll Db4objects.Db4o.Linq.dll Mono.Cecil.dll Cecil.FlowAnalysis.dll ~/lib

db4o DB

RDBで使用したデータ定義用SQLファイルのようなものは必要ありませんが、db4o DBに登録するオブジェクト用のクラス(永続化対象クラス)が必要になります。今までの記事で使用したProductsテーブルを模したProductクラス、およびテストデータ登録用のコード(C#)を用意します。登録するデータの内容は、今までの記事で使用したものと同様です。

 作業する上でのディレクトリ構造は、下表の通りとします。
ディレクトリファイル
~/data/db4oTestData.db4o
~/src/cs/db4oExampleProduct.cs
~/src/cs/db4oExample/Teststoredata.cs
Productクラス
[Product.cs]
  1. using System;  
  2.   
  3. namespace db4oExample  
  4. {  
  5.   public class Product  
  6.   {  
  7.     int      _id;  
  8.     string   _name;  
  9.     decimal? _price;  
  10.     string   _description;  
  11.   
  12.     public Product()  
  13.     : this(0, nullnullnull)  
  14.     {  
  15.     }  
  16.   
  17.     public Product(int id, string name, decimal? price, string description)  
  18.     {  
  19.       _id          = id;  
  20.       _name        = name;  
  21.       _price       = price;  
  22.       _description = description;  
  23.     }  
  24.   
  25.     public int Id  
  26.     {  
  27.       set { _id = value; }  
  28.       get { return _id; }  
  29.     }  
  30.   
  31.     public string Name  
  32.     {  
  33.       set { _name = value; }  
  34.       get { return _name; }  
  35.     }  
  36.   
  37.     public decimal? Price  
  38.     {  
  39.       set { _price = value; }  
  40.       get { return _price; }  
  41.     }  
  42.   
  43.     public string Description  
  44.     {  
  45.       set { _description = value; }  
  46.       get { return _description; }  
  47.     }  
  48.   
  49.     public override string ToString()  
  50.     {  
  51.       return "ID:" + _id + " NAME:" + _name + " PRICE:" + _price + " DESCRIPTION:" + _description;  
  52.     }  
  53.   }  
  54. }  
ライブラリとしてビルドします。

[Product.cs のビルド]
$ gmcs -t:library -out:./Test/db4oExample.dll Product.cs
テストデータ登録
[storedata.cs]
  1. using System;  
  2. using Db4objects.Db4o;  
  3.   
  4. using db4oExample;  
  5.   
  6. namespace db4oExample.Test  
  7. {  
  8.   public class StoreData  
  9.   {  
  10.     public static void Main(string[] args)  
  11.     {  
  12.       string dbfile = "/home/sta/data/db4o/TestData.db4o";  
  13.   
  14.       using (IObjectContainer db = Db4oFactory.OpenFile(dbfile))  
  15.       {  
  16.         IObjectSet results = db.QueryByExample(typeof(Product));  
  17.   
  18.         // DELETE  
  19.         Console.WriteLine("削除件数 = {0}", results.Size());  
  20.         foreach (Product p in results)  
  21.         {  
  22.           Console.WriteLine("DELETE!:{0}", p);  
  23.           db.Delete(p);  
  24.         }  
  25.   
  26.         // STORE  
  27.         db.Store(new Product(0, "db4o"null"db4o 7.4"));  
  28.         db.Store(new Product(1, "Clamp", 12.48M, "Workbench clamp"));  
  29.         db.Store(new Product(50, "Screwdriver", 3.17M, "Flat head"));  
  30.         db.Store(new Product(75, "Tire Bar"null"Tool for changing tires."));  
  31.         db.Store(new Product(3000, "3mm Bracket", 0.52M, null));  
  32.   
  33.         // UPDATE  
  34.         IObjectSet result = db.QueryByExample(new Product(50, nullnullnull));  
  35.         Product found = (Product)result.Next();  
  36.         found.Name = "Flat Head Screwdriver";  
  37.         db.Store(found);  
  38.   
  39.         // COMMIT  
  40.         db.Commit();  
  41.   
  42.         results = db.QueryByExample(typeof(Product));  
  43.         Console.WriteLine("登録件数 = {0}", results.Size());  
  44.         foreach (Product p in results)  
  45.         {  
  46.           Console.WriteLine("STORED!:{0}", p);  
  47.         }  
  48.       }  
  49.     }  
  50.   }  
  51. }  
  52. /* 
  53. * ビルド: 
  54. * 
  55. *   gmcs -r:Db4objects.Db4o.dll,db4oExample.dll storedata.cs 
  56. * 
  57. * 実行: 
  58. * 
  59. *   mono storedata.exe 
  60. * 
  61. */  
[実行例]
$ mono storedata.exe
削除件数 = 0
登録件数 = 5
STORED!:ID:0 NAME:db4o PRICE: DESCRIPTION:db4o 7.4
STORED!:ID:3000 NAME:3mm Bracket PRICE:0.52 DESCRIPTION:
STORED!:ID:1 NAME:Clamp PRICE:12.48 DESCRIPTION:Workbench clamp
STORED!:ID:50 NAME:Flat Head Screwdriver PRICE:3.17 DESCRIPTION:Flat head
STORED!:ID:75 NAME:Tire Bar PRICE: DESCRIPTION:Tool for changing tires.

 ここで、一通りのDB操作を行っているので、それらについて解説します。
Db4oFactory.OpenFile
Db4oFactory.OpenFileメソッドによりdb4o DBのオープンを行います。これは単なるローカルファイルとしてオープンするモードになります。該当するdb4o DBファイルが存在しない場合は、新規に作成されます。その他に、Embeded ServerモードやNetwork Serverモードでのオープンがあります。

OpenFileメソッドによって返される、ObjectContainerオブジェクトの次のメソッドを使用して、DB操作を行えます。
QueryByExample
db4oで用意されている簡易クエリ機能でQuery By Example(QBE)と呼ばれています。
  1. QueryByExample(typeof(Product))  

  1. QueryByExample(new Product())  
は同様の結果(すべてのProductオブジェクト)を返します。

 その他に、Native Query(NQ)SODA、そして、db4o 7.2からはLINQがクエリ機能として用意されています。
Store
オブジェクトの登録、更新を行うメソッドです。更新前に、既存の更新対象オブジェクトを検索しておき、その内容を変更したものをメソッドの引数として渡します。

 db4oではRDBのTABLE定義におけるPRIMARY KEYに該当する設定は存在しないようです。なので、KEYとしたいフィールドに同じ値をもつオブジェクトを作成し、Storeメソッドに渡しても、更新とはされず、同じ値をもつオブジェクトが登録されてしまいます。
Delete
更新と同様に、既存のオブジェクトを検索した後、それをDeleteメソッドの引数として渡します。
Commit
db4o DBをオープンした時にトランザクションは自動的に開始されます。また、クローズした時にも自動的にコミットが発行されますが、明示的に指定することも可能です。

 Monoで他のDBも使ってみたよ!+(db4o、NHibernate編)2 へ続く。

0 件のコメント:

コメントを投稿