ADO.NET 2.0 OdbcCommandのパラメータ付きクエリ
ADO.NET 2.0のOdbcCommandにはパラメータ付きクエリがあるが、意外とわかりづらい部分があるので書き留めておく。
まず、SqlCommandでは、パラメータ付きクエリを実現するために以下のようにパラメータを「@」をつけて表現する。
SqlConnection conn = new SqlConnection("ODBC接続文字列"); conn.Open(); String insertSQL = "INSERT INTO users(id, name) VALUES(@id, @name);"; SqlCommand command = new SqlCommand(insertSQL, conn); command.Parameters.AddWithValue("@id", 1); command.Parameters.AddWithValue("@name", "Joe"); command.ExecuteNonQuery();
同じようにODBCでもうまく行くと思っていたので、PostgreSQLを用いて以下のようにパラメータとして「@」を用いてOdbcCommandでパラメータ付きクエリを実装したところ、うまくいかなかった。OdbcException例外がスローされてしまう。
using System; using System.Collections.Generic; using System.Linq; using System.Data; using System.Data.Odbc; class Program { static void Main(string[] args) { String connStr = "ODBC接続文字列"; OdbcConnection conn = new OdbcConnection(connStr); conn.Open(); String insertSQL = "INSERT INTO users(id, name) " + "VALUES(@id, @name);"; OdbcCommand command = new OdbcCommand(insertSQL, conn); command.Parameters.AddWithValue("@id", 1); command.Parameters.AddWithValue("@name", "Joe"); command.ExecuteNonQuery(); } }
command.ExecuteNonQueryで以下のようなOdbcExceptionが発生する。
ERROR [42703] ERROR: 列"id"は存在しません; Error while executing the query
PostgreSQLのエラーコードを探してみると「42703」は「未定義列」となっている。(http://www.postgresql.jp/document/pg803doc/html/errcodes-appendix.html より)
さらに、PostgreSQLのログ(PostgreSQLのインストールディレクトリ\data\pg_logの下のpostgresql-yyyy-mm-dd_hhMMss.log)を見てみると、以下のようなエラーが出ていた。パラメータクエリがそのままの形でPostgreSQLに流れてしまっているようだ。
2010-05-04 10:51:29 JST ERROR: 列"id"は存在しません(文字位置 37) 2010-05-04 10:51:29 JST ステートメント: INSERT INTO users(id, name) VALUES(@id, @name);
色々調べてみると、以下のコードのようにパラメータとして「?」を使うと上手くいくことがわかった。
using System; using System.Collections.Generic; using System.Linq; using System.Data; using System.Data.Odbc; class Program { static void Main(string[] args) { String connStr = "ODBC接続文字列"; OdbcConnection conn = new OdbcConnection(connStr); conn.Open(); String insertSQL = "INSERT INTO users(id, name) " + "VALUES(?, ?);"; OdbcCommand command = new OdbcCommand(insertSQL, conn); command.Parameters.AddWithValue("@id", 1); command.Parameters.AddWithValue("@name", "Joe"); command.ExecuteNonQuery(); } }
このINSERTクエリをOdbcDataAdapterとDataTableを用いると以下のようになる
using System; using System.Collections.Generic; using System.Linq; using System.Data; using System.Data.Odbc; class Program { static void Main(string[] args) { String connStr = "接続文字列"; OdbcConnection conn = new OdbcConnection(connStr); OdbcDataAdapter da = new OdbcDataAdapter(connStr, conn); DataColumn idCol = new DataColumn("id", typeof(Int32)); DataColumn nameCol = new DataColumn("name", typeof(String)); DataTable table = new DataTable(); table.Columns.Add(idCol); table.Columns.Add(nameCol); DataRow row = table.NewRow(); row[idCol] = 1; row[nameCol] = "Smith"; table.Rows.Add(row); da.InsertCommand = new OdbcCommand("INSERT INTO users(id, name) VALUES(?, ?);", conn); da.InsertCommand.Parameters.Add("@id", OdbcType.Int); da.InsertCommand.Parameters.Add("@name", OdbcType.Text); da.Update(table); } }
なんとかこれで解決。良かったです。
参考