taediumの日記

2011-05-22

[][] 次バージョンでPowerShellのサポート

手許のコードではこんな感じでアクセスできるようになりました。特別にAssemblyを作る必要はなく、Soma.Core.dllをロードするだけ(FSharp.Core.dllやFSharp.PowerPack.dllがGACにあるなら)。

2WaySQLも使える。Queryの結果はHashtableのIListでかえってきます。

PowerShell
$somaAssemblyPath = "$pwd\ps\Soma.Core.dll"

[system.reflection.assembly]::LoadFrom($somaAssemblyPath)

$invariant = "System.Data.SqlClient"
$connectionString = "Data Source=.;Initial Catalog=tempdb;Integrated Security=True"
$dialect = new-object Soma.Core.MsSqlDialect
$config = new-object Soma.Core.PlainConfig $invariant, $connectionString, $dialect
$db = new-object Soma.Core.PlainDb $config

$setup = @"
drop table person;
create table person (
    id int identity primary key,
    name varchar(100),
    age int
);
insert into person (name, age) values ('aaa', 20);
insert into person (name, age) values ('bbb', 30);
insert into person (name, age) values ('ccc', 40);
"@

$db.Execute($setup)

$db.Query("select * from Person where id = /*id*/0", @{id=2}) 

$db.QueryOnDemand("select * from Person") 

次バージョン(0.14.0.0)で正式にサポートする予定です。


[][] PowerShellからSomaを使ってDBアクセス

いろいろやってみましたが、アダプタとなるアセンブリを作ってしまうのが一番簡単。

次のクラスをSoma.PowerShell.dllというアセンブリに含めます。

Somaを呼び出すC#のクラス
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Soma.PowerShell
{
    internal class Config : Soma.Core.MsSqlConfig
    {
        public override string ConnectionString { get { return "Data Source=.;Initial Catalog=tempdb;Integrated Security=True"; } }
    }

    public class Db
    {
        private readonly Soma.Core.Db _db = new Soma.Core.Db(new Config());

        public IEnumerable<IDictionary> Query(string sql)
        {
            return _db.QueryOnDemand<Soma.Core.IDynamicObject>(sql).Select(d => {
                var hashTable = new Hashtable();
                foreach (var pair in d)
                {
                    hashTable.Add(pair.Key, pair.Value);
                }
                return hashTable;
            });
        }

        public int Execute(string sql)
        {
            return _db.Execute(sql);
        }

    }
}

PowerShellでは、Soma.Core.dllと上で作ったSoma.PowerShell.dllをロードします。

ロードしたあとは、上で書いたSoma.PowerShell.Dbクラスをインスタンス化すれば好きなSQLを実行できます。

PowerShell
$somaAssemblyPath = "$pwd\ps\Soma.Core.dll"
$somaPowerShellAssemblyPath = "$pwd\ps\Soma.PowerShell.dll"

[system.reflection.assembly]::LoadFrom($somaAssemblyPath)
[system.reflection.assembly]::LoadFrom($somaPowerShellAssemblyPath)

$db = new-object -TypeName Soma.PowerShell.Db

$setup = @"
drop table person;
create table person (
    id int identity primary key,
    name varchar(100),
    age int
);
insert into person (name, age) values ('aaa', 20);
insert into person (name, age) values ('bbb', 30);
insert into person (name, age) values ('ccc', 40);
"@

$db.Execute($setup)

$db.Query("select * from Person") 

わかったこととか。

  • GACに入っていないアセンブリに依存したコードを渡してAdd-Typeコマンドレットを呼び出すことはできないかもしれない(やり方わからなかった)。でもAdd-Typeを使わずアセンブリつくってしまえばいい。
  • PowerShellではジェネリックなメソッドやクラスを扱いにくい。ジェネリックを使っていないPowerShell用のインタフェースを作ってあげたほうがいい。アセンブリをつくるか、PowerShellのコマンドレットとか関数でがんばるか。
  • PowerShellでハッシュテーブル用の構文を使うには、System.Collections.IDictionaryを実装していないとだめっぽい。System.Collections.Generic.IDictionary<TKey,TValue>ではだめだった。

Soma本体のほうにPowerShellから呼び出しやすくする機能を設けたほうがいいか検討してみることにします。