2007年11月9日金曜日

[.NET]ADO.NET(ODP.NET)

ADO.NETでは、今までバラバラだったDBに関係するクラスが共通のインタフェースを実装したことと、FactoryMethodによるインスタンス生成のラップにより、どんなデータベースにつないでいるかを意識する必要が無くなりました。実装はこんなかんじ。



DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
using (DbConnection con = factory.CreateConnection())
using (DbCommand cmd = factory.CreateCommand())
{
    con.ConnectionString = "User Id=scott; Password=tiger; Data Source=ora10g";
    con.Open();
    cmd.Connection = con;
    DbDataReader reader = cmd.ExecuteReader("SELECT * FROM TEST_TABLE");
        :
        :
        :
    reader.Dispose();
}


ところが、この機構を使った場合、ODP.NETの拡張機能が使えない(使いづらい)ことになってしまいます。まぁ共通I/Fなので当たり前といえば当たり前なんですが。。。で、何が痛いかというと、

  • OracleCommand.BindByNameプロパティが使えない(キャストすれば。。。)
  • OracleCommand.OracleDbTypeプロパティが使えない(キャストすれば。。。)

です。で、何が不便かというと、

  • BindByNameの影響で、bind変数「:USER_ID」としてもOleDB同様「?」相当
  • OracleDbTypeの影響で、CHAR型のbind変数は、同じサイズにPadLeftしないとヒットしない

という問題が発生します。
だからといってキャストするのはイヤだしOracleしか使わないと決まっているシステムであったため、今回は直接ODP.NETのクラスを生成することにしました。とはいえDispose漏れの考慮からラップクラスは用意しています。

しかし、OLE DBやSQLServerの場合はDbProviderFactoryでいけるはず。Oracle以外にあたったらこの方式が最適なんでしょう。SQLServerは何もしなくても「@USER_ID」でbind出来ちゃうんだろうか。出来るのであればなぜODP.NETはそうじゃないんだろう?


あぁODP.NETでもこの問題が解決できればなぁ。。。

0 件のコメント: