2009年8月31日月曜日

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

このエントリーをはてなブックマークに追加

DBアクセス

接続確認

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

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

[Productオブジェクトの全件取得(Idの昇順)]
using System;
using System.Collections.Generic; // NQ, LINQ
using System.Linq;                // LINQ
using Db4objects.Db4o;
using Db4objects.Db4o.Query;      // SODA
using Db4objects.Db4o.Linq;       // LINQ

using db4oExample;

namespace db4oExample.Test
{
  public class Query1
  {
    public static void Main(string[] args)
    {
      string dbfile = "/home/sta/data/db4o/TestData.db4o";

      using (IObjectContainer db = Db4oFactory.OpenFile(dbfile))
      {
        // Productオブジェクトの全件取得(Idの昇順)
        #region Query

        // QBE
        // ソート条件の設定は不可
        //IObjectSet results = db.QueryByExample(typeof(Product));
        // 結果セットに対してソート
        IObjectSet cache = db.QueryByExample(typeof(Product));
        var results = cache.Cast<Product>().OrderBy(p => p.Id);

        #endregion

        foreach (Product p in results)
        {
          Console.WriteLine(p);
        }
      }
    }
  }
}
/*
* ビルド:
*
*   gmcs -r:Db4objects.Db4o.dll,Db4objects.Db4o.Linq.dll,db4oExample.dll query1.cs
*
* 実行:
*
*   mono query1.exe
*
*/

[Productオブジェクトの取得(Idによる検索)]
using System;
using System.Collections.Generic; // NQ, LINQ
using System.Linq;                // LINQ
using Db4objects.Db4o;
using Db4objects.Db4o.Query;      // SODA
using Db4objects.Db4o.Linq;       // LINQ

using db4oExample;

namespace db4oExample.Test
{
  public class Query2
  {
    public static void Main(string[] args)
    {
      string dbfile = "/home/sta/data/db4o/TestData.db4o";

      string i;
      int id;

      Console.Write("ID?> ");
      i = Console.ReadLine();

      if (!(Int32.TryParse(i, out id)))
      {
        Console.WriteLine("整数値を入力して下さい。入力値 = {0}", i);
        return;
      }

      using (IObjectContainer db = Db4oFactory.OpenFile(dbfile))
      {
        // Productオブジェクトの取得(Idによる検索)
        #region Query

        // QBE
        IObjectSet result = db.QueryByExample(new Product(id, null, null, null));

        #endregion

        foreach (Product p in result)
        {
          Console.WriteLine("FOUND!:{0}", p);
        }
      }
    }
  }
}
/*
* ビルド:
*
*   gmcs -r:Db4objects.Db4o.dll,Db4objects.Db4o.Linq.dll,db4oExample.dll query2.cs 
*
* 実行:
*
*   mono query2.exe
*
*/
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の昇順)]
// NQ
IList<Product> results = db.Query<Product>
(
  delegate(Product p)
  {
    return true;
  },
  new Comparison<Product>
  (
    delegate(Product p1, Product p2)
    {
      return p1.Id.CompareTo(p2.Id);
    }
  )
);

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

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

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

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

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

[Embeded Serverモード]
...
IObjectServer server = Db4oFactory.OpenServer(dbfile, 0); // PORT=0

try
{
  using (IObjectContainer client1 = server.OpenClient())
  using (IObjectContainer client2 = server.OpenClient()) // 別のクライアントが必要な場合
  {
    // 各Query
  }
}
finally
{
  if (server != null)
  {
    server.Close();
  }
}
...

[Network Serverモード:サーバ側]
...
IObjectServer server = null;

try
{
  server = Db4oFactory.OpenServer(dbfile, 4649); // 任意のPORT番号
  server.GrantAccess("sta", "password");

  Console.WriteLine("Server Started.\n### Hit some keys to stop the server ###");
  Console.ReadLine();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}
finally
{
  if (server != null)
  {
    server.Close();
  }

  Console.WriteLine("Server Stopped.");
}
...

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

0 件のコメント:

コメントを投稿