今回はNpgsqlDataAdapterを使ったINSERTの解説です。
注意点も解説しつつ幾つかの手法を紹介します。
Npgsqlの本家情報は
私の作成するサンプルソースファイルは
基本的なテーブルは下記構成となります。
テーブル名 | 型 | 概要 |
---|---|---|
id | serial | 自動的にセットされる通し番号 |
time | timestamp | トランザクション開始時刻または入力された日付 |
name | text | 任意の文字列 |
numeric | integer | 任意の数値 |
時間はCREATE TABLEで「time timestamp DEFAULT clock_timestamp()」としており、意図的に時間をセットできますが、何もINSERTしなければ自動的に現在の時間がセットされます。
このテーブルに下記2つのデータが存在しているのを前提として説明します。
id | time | name | numeric |
---|---|---|---|
1 | INSERTした時間 | a | 1 |
2 | INSERTした時間 | b | 2 |
INSERTのきほん
まずは一番オーソドックスで、かつ一番利用頻度が高い手法です。
NpgsqlDataAdapterのコンストラクタ引数は4つありますが、うち3つはSELECTに関する変数や文字列が引数となります。
なにはともあれ運用が始まればSELECTでデータを取得しなきゃ始まらないですからね。
DataTableを用意しておきNpgsqlDataAdapterのインスタンスを生成したら「Fill」メソッドでデータを取得します。
FillメソッドはDataTableやDataSetを引数として渡せますので、その場で最適な引数を渡してください。
次に7~10行目でDataTableのdtに1つデータを追加してみます。
これで準備OKとはなりません。
- INSERTするデータ用NpgsqlCommandを作る。
- INSERTするデータの数だけNpgsqlParameterを作る。
- NpgsqlParameteのParameterNameとSourceColumnを適切に設定する。
- NpgsqlCommandのParameters.Addメソッドを実行し作ったNpgsqlParameteを渡す。
- NpgsqlDataAdapterのInsertCommandプロパティへNpgsqlCommandを渡す。
- NpgsqlDataAdapteのUpdateメソッドを実行する。
文章にすると何となく面倒な感じがしますが、全て必要な事です。
手順1が上記サンプルコードの12~14行目が該当します。
14行目で実際に実行するクエリ文と渡す値のパラメータをセットします。
手順,2,3,4はサンプルコード16~24行目が該当します。
NpgsqlParameterのParameterNameにはクエリ文で指定したパラメータ(@○○○)、SourceColumnにはデータベーステーブルの(またはDataTable)のカラム名を指定します。
そして手順5は26行目となります。
実際のINSERT実行は29行目ですが、正常にINSERTできなかった時のために例外「DBConcurrencyException」をキャッチできるようにすれば完璧です。
例外「DBConcurrencyException」はINSERTだけじゃなく、データが変更されるような動作でエラーが出た時に発生します。
INSERTするまでの手順は今までより少し長いですが、大量なデータを処理する場合はDataTableを触るだけで良いのでミスが減る可能性があります。
NpgsqlCommandBuilderを使った時の自動挿入カラムの注意点
NpgsqlにはNpgsqlCommandBuilderという便利な機能があります。
SELECTしたデータを基にINSERTクエリ等を自動的に生成してくれる機能です。
これを利用すればINSERTやUPDATE、DELETEのクエリ文は自分で作らなくてもOKです。
しかし落とし穴もあるので問題点を解説します。
上記サンプルプログラムはSELECTで全てのカラムデータを取得しますがDataTableに追加するのはカラム名「name」と「numeric」です。
このプログラムを実行した後にpgAdmin4でテーブルのデータ一覧を見ると自動挿入のidはきちんと値がセットされていますが、同じく自動挿入を期待しているtimeカラムはnullになっています。
NpgsqlCommandBuilderの「GetInsertCommand().CommandText」プロパティを見ると実行されるクエリ文が分かるのですが、それを見ると
INSERT INTO "db_PostgreTest"."public"."data" ("time", "name", "numeric") VALUES (@p1, @p2, @p3)
となっており、timeにもデータをINSERTしようとしています。
当然DataTableのカラム名timeには何もデータをセットしていません。
同じくカラム名idにもデータは入れてませんが、NpgsqlCommandBuilderは自動挿入と判断しているらしくクエリ文にはidにINSERTする部分は見つかりません。
このように自分が意図する結果にならないケースがありますのでNpgsqlCommandBuilderを使うのは注意が必要です。
NpgsqlCommandBuilderを使った時の自動挿入カラムの解決
上記意図しないINSERTで自動的にセットする値が入らない場合の解決策は至って簡単です。
SELECTの時に必要ではないデータを読み込まなければいいだけです。
上記サンプルプログラムは「id」、「name」、「numeric」だけをSELECTしていますが、この結果NpgsqlCommandBuilderで生成されたINSERT文は
INSERT INTO "db_PostgreTest"."public"."data" ("name", "numeric") VALUES (@p1, @p2)
となり、timeにINSERTされる事はありませんし、timeには自動的にINSERTされた時の時間がセットされます。
もしSELECTしたデータのtimeが必要であればNpgsqlDataAdapterのUpdateメソッドを実行する直前にDataTableのtimeにDateTime.Nowプロパティの値をセットすればほぼ正確なINSERTしたタイミングの時間がセットされます。
0 件のコメント:
コメントを投稿