第7回 マスタ/詳細テーブルにおける更新処理連載:Visual Studio 2005によるWindowsデータベース・プログラミング(2/4 ページ)

» 2007年11月27日 00時00分 公開
[遠藤孝信デジタルアドバンテージ]

■Fillメソッド呼び出し時の制約違反

 外部キー制約の設定を行ってからプログラムを実行してみると、これまで発生していなかった制約違反の例外がいきなり発生してしまいます。

図3 Fillメソッド呼び出し時の制約違反における例外発生

 これは、子データテーブルにレコードを読み込んだ瞬間に、そのレコードに対する親テーブルのレコードがないという状態が発生するためです。

 具体的には、次の図4のように、OrderID番号=10248の注文明細データをデータベースから読み込んだのに、注文データテーブルにOrderID番号=10248の注文データが存在しないといった状態になってしまいます。

図4 外部キー制約違反を発生させるレコードの読み込み

 注文データテーブルにレコードを読み込む処理は、例外が発生している次の行のFillメソッド呼び出しであり、この時点では注文データテーブルは空っぽなので、当然といえば当然です。

 対処としては、データセットのEnforceConstraintsプロパティをFalseに設定して一時的に制約をオフにする(図3の例外ウィンドウのヒントの1行目にある方法)などがありますが、最も簡単なのは、Fillメソッドを呼び出している2行の順番を入れ替えて、親テーブルで先にレコードを読み込むようにします。

 つまり、

Me.注文明細TableAdapter.Fill(Me.NORTHWNDDataSet.注文明細)
Me.注文TableAdapter.Fill(Me.NORTHWNDDataSet.注文)


の2行の順番を入れ替えて、

Me.注文TableAdapter.Fill(Me.NORTHWNDDataSet.注文)
Me.注文明細TableAdapter.Fill(Me.NORTHWNDDataSet.注文明細)


としておきます。

■注文明細データ入力時の制約違反

 レコードはうまく読み込めるようになりましたが、そのまま続けてデータの入力を行っていると、もう1つ致命的なエラーに遭遇します。

 それは、ツールバーの[+]ボタンをクリックして注文データを新規追加した後、その注文明細データをグリッドに入力し、グリッドの次の行にフォーカスを移動して([リターン]キーを押してもよい)、グリッドへの入力を完了させたときに発生します*4

図5 新規の注文データで注文明細データ入力完了時に発生する例外
  (1)[+]ボタンをクリックして注文データを新規追加する。
  (2)グリッドに注文明細データを追加して入力を完了させる。
  (3)例外が発生。

*4 本サンプル・プログラムでは取りあえず正常系のデータ入力しか扱っていません。異常系のデータ入力(例えばグリッドでUnitPrice列に値を入力しなかった場合など)では例外が多々発生します。各入力項目では本来バリデーション・チェックが必要ですが、本稿ではすべて省略しています。


 これがなぜ起きるかというと、グリッドに入力した注文明細データは注文明細データテーブルに反映されたのに、注文データの方が注文データテーブルにまだ反映されていないためです。

図6 外部キー制約違反を発生させる新規レコードの追加
グリッドで追加されたレコードは注文明細データテーブルに追加されたが、その親レコードがまだ注文データテーブルに追加されていないため、例外が発生する。

 このような状態は、新規作成した注文データの入力を完了させていないために起こります。

 第4回の最後でも少し解説しているように、グリッドでの入力は行を移動すると自動的に完了し、BindingSourceコンポーネントを通じてデータテーブルに反映されます(編集中の行については、そのBindingSourceコンポーネントでEndEditメソッドを呼び出すことにより確定させることができます。この処理は[データの保存]ボタンがクリックされたときに必要になります)。

 これに対し、注文データの入力(アプリケーション画面の上半分での入力)を確定させる処理はまだどこにもありません。つまり、注文明細データが入力される時点で、注文データ部分のBindingSourceコンポーネントである注文BindingSourceオブジェクトのEndEditメソッドを呼び出しておく必要があります。

 ということで、DataGridViewコントロールのイベント一覧を眺めてみると、新しい行が追加されたときに発生する「RowsAdded」というイベントが用意されています。このイベント・ハンドラを作成し、次のようにEndEditメソッドの呼び出しを追加しておきます。

Private Sub 注文明細DataGridView_RowsAdded(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewRowsAddedEventArgs) Handles 注文明細DataGridView.RowsAdded

  Me.注文BindingSource.EndEdit()

End Sub

DataGridViewコントロールのRowsAddedイベント・ハンドラ
グリッドに新しい行が追加された時点で、そのレコードの親となる注文データの入力を完了させる。

 このイベント・ハンドラの追加により、新規データの追加もできるようになりました。では本題であるデータベースの更新に移りましょう。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。