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();
}
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 件のコメント:
コメントを投稿