2009年8月31日月曜日

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


DBアクセス

接続確認

簡単な検索(全件検索、Idによる検索)を行うコードを用いて、db4oで用意されているクエリ機能(QBE、NQ、SODA、LINQ)、および、db4o DBのServerモードでのオープンについて解説します。

 ベースとなるコード(C#)は次になります。

[Productオブジェクトの全件取得(Idの昇順)]
  1. using System;  
  2. using System.Collections.Generic; // NQ, LINQ  
  3. using System.Linq;                // LINQ  
  4. using Db4objects.Db4o;  
  5. using Db4objects.Db4o.Query;      // SODA  
  6. using Db4objects.Db4o.Linq;       // LINQ  
  7.   
  8. using db4oExample;  
  9.   
  10. namespace db4oExample.Test  
  11. {  
  12.   public class Query1  
  13.   {  
  14.     public static void Main(string[] args)  
  15.     {  
  16.       string dbfile = "/home/sta/data/db4o/TestData.db4o";  
  17.   
  18.       using (IObjectContainer db = Db4oFactory.OpenFile(dbfile))  
  19.       {  
  20.         // Productオブジェクトの全件取得(Idの昇順)  
  21.         #region Query  
  22.   
  23.         // QBE  
  24.         // ソート条件の設定は不可  
  25.         //IObjectSet results = db.QueryByExample(typeof(Product));  
  26.         // 結果セットに対してソート  
  27.         IObjectSet cache = db.QueryByExample(typeof(Product));  
  28.         var results = cache.Cast<Product>().OrderBy(p => p.Id);  
  29.  
  30.         #endregion  
  31.   
  32.         foreach (Product p in results)  
  33.         {  
  34.           Console.WriteLine(p);  
  35.         }  
  36.       }  
  37.     }  
  38.   }  
  39. }  
  40. /* 
  41. * ビルド: 
  42. * 
  43. *   gmcs -r:Db4objects.Db4o.dll,Db4objects.Db4o.Linq.dll,db4oExample.dll query1.cs 
  44. * 
  45. * 実行: 
  46. * 
  47. *   mono query1.exe 
  48. * 
  49. */  

[Productオブジェクトの取得(Idによる検索)]
  1. using System;  
  2. using System.Collections.Generic; // NQ, LINQ  
  3. using System.Linq;                // LINQ  
  4. using Db4objects.Db4o;  
  5. using Db4objects.Db4o.Query;      // SODA  
  6. using Db4objects.Db4o.Linq;       // LINQ  
  7.   
  8. using db4oExample;  
  9.   
  10. namespace db4oExample.Test  
  11. {  
  12.   public class Query2  
  13.   {  
  14.     public static void Main(string[] args)  
  15.     {  
  16.       string dbfile = "/home/sta/data/db4o/TestData.db4o";  
  17.   
  18.       string i;  
  19.       int id;  
  20.   
  21.       Console.Write("ID?> ");  
  22.       i = Console.ReadLine();  
  23.   
  24.       if (!(Int32.TryParse(i, out id)))  
  25.       {  
  26.         Console.WriteLine("整数値を入力して下さい。入力値 = {0}", i);  
  27.         return;  
  28.       }  
  29.   
  30.       using (IObjectContainer db = Db4oFactory.OpenFile(dbfile))  
  31.       {  
  32.         // Productオブジェクトの取得(Idによる検索)  
  33.         #region Query  
  34.   
  35.         // QBE  
  36.         IObjectSet result = db.QueryByExample(new Product(id, nullnullnull));  
  37.  
  38.         #endregion  
  39.   
  40.         foreach (Product p in result)  
  41.         {  
  42.           Console.WriteLine("FOUND!:{0}", p);  
  43.         }  
  44.       }  
  45.     }  
  46.   }  
  47. }  
  48. /* 
  49. * ビルド: 
  50. * 
  51. *   gmcs -r:Db4objects.Db4o.dll,Db4objects.Db4o.Linq.dll,db4oExample.dll query2.cs  
  52. * 
  53. * 実行: 
  54. * 
  55. *   mono query2.exe 
  56. * 
  57. */  
QBE
QBE(Query By Example)はdb4oで用意されている簡易クエリ機能ですが、簡易ゆえの限界があります。例えば、後述する各クエリではクエリの命令セットの中に、ソート条件の設定が可能ですが、QBEではできません。検索条件も設定した値(!初期値)のANDだけで、複雑な条件設定はできません。また、初期値による検索は全件が返されてしまいます。

[実行例]
$ mono query2.exe
ID?> 1
FOUND!:ID:1 NAME:Clamp PRICE:12.48 DESCRIPTION:Workbench clamp
$ mono query2.exe
ID?> 0
FOUND!:ID:0 NAME:db4o PRICE: DESCRIPTION:db4o 7.4
FOUND!:ID:3000 NAME:3mm Bracket PRICE:0.52 DESCRIPTION:
FOUND!:ID:1 NAME:Clamp PRICE:12.48 DESCRIPTION:Workbench clamp
FOUND!:ID:50 NAME:Flat Head Screwdriver PRICE:3.17 DESCRIPTION:Flat head
FOUND!:ID:75 NAME:Tire Bar PRICE: DESCRIPTION:Tool for changing tires.
NQ
QBEを次のNQ(Native Query)に置き換え可能です。

[Productオブジェクトの全件取得(Idの昇順)]
  1. // NQ  
  2. IList<Product> results = db.Query<Product>  
  3. (  
  4.   delegate(Product p)  
  5.   {  
  6.     return true;  
  7.   },  
  8.   new Comparison<Product>  
  9.   (  
  10.     delegate(Product p1, Product p2)  
  11.     {  
  12.       return p1.Id.CompareTo(p2.Id);  
  13.     }  
  14.   )  
  15. );  

[Productオブジェクトの取得(Idによる検索)]
  1. // NQ  
  2. IList<Product> result = db.Query<Product>  
  3. (  
  4.   delegate(Product p)  
  5.   {  
  6.     return ( p.Id == id );  
  7.   }  
  8. );  
NQはdb4oでのメインクエリと位置づけられているようですが、単純な昇順の設定でこの記述は遠慮したいところです。
SODA
QBEを次のSODA Queryに置き換え可能です。

[Productオブジェクトの全件取得(Idの昇順)]
  1. // SODA  
  2. IQuery query = db.Query();  
  3. query.Constrain(typeof(Product));  
  4. query.Descend("_id").OrderAscending();  
  5. IObjectSet results = query.Execute();  

[Productオブジェクトの取得(Idによる検索)]
  1. // SODA  
  2. IQuery query = db.Query();  
  3. query.Constrain(typeof(Product));  
  4. query.Descend("_id").Constrain(id);  
  5. IObjectSet result = query.Execute();  
SODAはdb4oで提供されているクエリ機能の中で下位レベルのクエリとされ、実際、他のクエリはSODAに変換されて実行ということなので、最初からSODAで記述すれば、パフォーマンス的にはよいということになります。
LINQ
QBEを次のLINQに置き換え可能です。

[Productオブジェクトの全件取得(Idの昇順)]
  1. // LINQ  
  2. var results = from Product p in db  
  3.   orderby p.Id  
  4.   select p;  

[Productオブジェクトの取得(Idによる検索)]
  1. // LINQ  
  2. var result = from Product p in db  
  3.   where p.Id == id  
  4.   select p;  
可読性に勝り、.NETで提供されている汎用的なクエリでもあるので、メインクエリとして使用されるようになるでしょうか。
Db4oFactory.OpenServer
Db4oFactory.OpenFileメソッドでオープンすると、ファイルとしてのオープンになりますが、Db4oFactory.OpenServerメソッドを使用することで、Client/Server形式のDBアクセスが可能になります。OpenServerメソッドの引数として渡すPORT番号の値により、ネットワークを経由しないEmbeded Serverモード(PORT=0)、ネットーワを経由するNetwor Serverモード(PORT=0以外)に分かれます。

[Embeded Serverモード]
  1. ...  
  2. IObjectServer server = Db4oFactory.OpenServer(dbfile, 0); // PORT=0  
  3.   
  4. try  
  5. {  
  6.   using (IObjectContainer client1 = server.OpenClient())  
  7.   using (IObjectContainer client2 = server.OpenClient()) // 別のクライアントが必要な場合  
  8.   {  
  9.     // 各Query  
  10.   }  
  11. }  
  12. finally  
  13. {  
  14.   if (server != null)  
  15.   {  
  16.     server.Close();  
  17.   }  
  18. }  
  19. ...  

[Network Serverモード:サーバ側]
  1. ...  
  2. IObjectServer server = null;  
  3.   
  4. try  
  5. {  
  6.   server = Db4oFactory.OpenServer(dbfile, 4649); // 任意のPORT番号  
  7.   server.GrantAccess("sta""password");  
  8.   
  9.   Console.WriteLine("Server Started.\n### Hit some keys to stop the server ###");  
  10.   Console.ReadLine();  
  11. }  
  12. catch (Exception ex)  
  13. {  
  14.   Console.WriteLine(ex.Message);  
  15. }  
  16. finally  
  17. {  
  18.   if (server != null)  
  19.   {  
  20.     server.Close();  
  21.   }  
  22.   
  23.   Console.WriteLine("Server Stopped.");  
  24. }  
  25. ...  

[Network Serverモード:クライアント側]
  1. ...  
  2. using (IObjectContainer client = Db4oFactory.OpenClient("localhost", 4649, "sta""password"))  
  3. {  
  4.   // 各Query  
  5. }  
  6. ...  
Monoで他のDBも使ってみたよ!+(db4o、NHibernate編)3 へ続く。

0 件のコメント:

コメントを投稿