2007年5月11日金曜日

.NET OracleのフィールドにDbNull.Valueを登録する際の注意

今日は不思議な事象にはまりました。
自力理解ができないので?@ITに投稿してみました^^;


現象
パラメータを使用して複数件のデータをOracleデータベースに更新する際、パラメータのDbTypeを設定せずに更新クエリーを実行するとOracleExceptionがThrowされる場合があります。

例えば、OracleテーブルのDate型フィールドに2件のデータを登録するとします。
1件目のデータがNowであれば更新クエリーは成功します。
 1件目:Now
 2件目:DbNull.Value

1件目のデータがDbNull.Valueであれば更新クエリーは2件目のデータを更新する際にOracleExceptionをThrowします。
 1件目:DbNull.Value
 2件目:Now

ThrowするException
ORA-01861: リテラルが書式文字列と一致しません。

パラメータのDbTypeを設定すれば例外はThrowされません。
SQLServerでは発生しないようです。


サンプルコード

    Private Sub Button1_Click(ByVal sender As System.ObjectByVal e As System.EventArgs) Handles Button1.Click


 

        'データテーブルオブジェクトを作成します。

        Dim table As New DataTable

        table.Columns.Add(New DataColumn("TESTDATE"GetType(Date)))

        Dim row As DataRow


 

        'データテーブルに1件目のデータを追加します。

        row = table.NewRow

        row("TESTDATE") = DBNull.Value

        table.Rows.Add(row)


 

        'データテーブルに2件目のデータを追加します。

        row = table.NewRow

        row("TESTDATE") = Now

        table.Rows.Add(row)


 

        'コネクションオブジェクトを作成します。

        Dim cnn As New OracleClient.OracleConnection

        cnn.ConnectionString = "接続文字列"


 

        'コマンドオブジェクトを作成します。

        Dim cmdInsert As New OracleClient.OracleCommand

        cmdInsert.Connection = cnn

        cmdInsert.CommandText = "INSERT INTO TESTTABLE (TESTDATE) VALUES (:TESTDATE)"


 

        'パラメータを作成します。

        Dim prm As New OracleClient.OracleParameter

        prm = cmdInsert.CreateParameter

        '--DbTypeを指定しないとExceptionが発生します。--

        prm.DbType = DbType.Date

        prm.ParameterName = "TESTDATE"

        prm.SourceColumn = "TESTDATE"

        cmdInsert.Parameters.Add(prm)


 

        'データテーブルの変更をデータベースへ反映します。

        Dim adp As New OracleClient.OracleDataAdapter

        adp.InsertCommand = cmdInsert

        adp.Update(tbl)

    End Sub


MSDNでOracleParameter.DbType プロパティを確認すると
パラメータの DbType プロパティ、OracleType プロパティ、および.Data.OracleClient.OracleParameter.Size プロパティは、.Data.OracleClient.OracleParameter.Value を設定することによって推論できます。したがって、これらを指定する必要はありません。とありました。

パラメータはValue値からDbTypeを推論します。
Oracle® Data Provider for .NET開発者ガイド の「ValueからのDbTypeおよびOracleDbType」の推論によると.Netデータ型がDateTimeのときOracleDbTypeはTimeStampを推論するようです。

つまり1件目のデータのパラメータValue値がDbNull.Valueの場合、OracleDbTypeをTimeStampと推論し2件目のデータでOracleDbTypeがDate型のデータをInsertしようとして例外がスローされるようです。
1件目のデータのパラメータValue値がDbNull.Value以外であればOracleDbTypeはDate型を推論するため、1件目のデータがNowであれば例外はスローされないということのようです。

0 件のコメント: