DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DataSet にバインドした DataGridView で新規追加時にエラー

環境/言語:[WindowsXP/Visual Basic 2005/.NET Framework 2.0/SQL Server Express 2005]
分類:[.NET]

2009/01/20(Tue) 06:04:47 編集(投稿者)

@IT の連載「データベースプログラミング入門」にて、
第1回〜第7回の途中まで進み、どうしてもわからないところがあって
つまづいてしまいました。

以下のページ

http://www.atmarkit.co.jp/fdotnet/vblab/vsdbprog_07/vsdbprog_07_02.html

の最後(DataGridView の RowsAdded イベントハンドラにてBindingSource の EndEdit メソッドを呼び出すコードの記述)まで進めたのですが、
解説にあるような動きをせず、エラーが出てプログラムが動きません。

 内容を簡単に説明しますと、
1枚のフォームの上半分に親データテーブル(注文レコード)1レコード分が詳細表示されており、フォームの下半分に子データテーブル(注文明細データテーブル)が DataGridView コントロールで一覧表示されています。(注文レコード配下の全ての注文明細レコードが DataGridView 上に一覧表示されています。)

 親データテーブル(注文データテーブル)と子データテーブル(注文明細データテーブル)は OrderID によって外部キー制約がかけられている状態で、親データテーブル内のレコード(注文レコード)にて OrderID が変更されると、そのレコード配下にある子データテーブルの全てのレコード(全ての明細レコード)の OrderID も変更されます。また、注文レコードが削除されると、その配下にある全ての明細レコードも削除されます。(はずです。まだここまで試していませんが、上記ページの解説によると、そのようになるようです。)

・エラーの再現手順
 上記のプログラムを実行し、フォーム上の BindingNavigator の「+」ボタンをクリックし、親データテーブル(注文データテーブル)のレコードを新規作成し、レコードに適当な値を記入します。その後、セーブ(データアダプタを介したデータベースへの登録処理)を行わずに、すぐに子データテーブル(注文明細データテーブル)にレコードを追加しようとすると、エラーが発生します。

 「+」ボタンをクリックすると、親データテーブル(注文データ)のレコードを新たに作るため、フォームの上下ともに空白の状態になります。この状態で、フォーム上半分に注文データを入力し、次に、下半分のデータグリッドに注文明細データを入力しようとした時にエラーが発生します。

 データグリッドは、新規追加用の行が1行だけある状態で、その行の任意の列(例えば Unit Price 列)をクリックすると、まず OrderID 列に自動的に親レコード(注文レコード)の OrderID 値が入力されます。そして、クリックしたセル(Unit Price 列)に 50000 と入力しようとしてテンキーの 5 を押すと、セルに一瞬 5 と表示された後、エラーが出てしまいます。

エラーの内容は、以下の通りです。

「System.ArgumentOutOfRangeException はハンドルされませんでした。
Message="指定された行インデックスが範囲外です。
 パラメータ名:rowIndex"

Source="System.Windows.Forms"
ParamName="rowIndex"
StackTrace:
場所 System.Windows.Forms.DataGridViewRowCollection.GetRowState(Int32 rowIndex)
場所 System.Windows.Forms.DataGridView.OnAddedRow_PostNotification(Int32 rowIndex)
場所 System.Windows.Forms.DataGridViewRowCollection.OnCollectionChanged_PostNotification(CollectionChangeAction cca, Int32 rowIndex, Int32 rowCount, DataGridViewRow dataGridViewRow, Boolean changeIsDeletion, Boolean changeIsInsertion, Boolean recreateNewRow, Point newCurrentCell)
場所 System.Windows.Forms.DataGridViewRowCollection.OnCollectionChanged(CollectionChangeEventArgs e, Int32 rowIndex, Int32 rowCount)
場所 System.Windows.Forms.DataGridViewRowCollection.AddInternal(Boolean newRow, Object[] values)
場所 System.Windows.Forms.DataGridView.AddNewRow(Boolean createdByEditing)
場所 System.Windows.Forms.DataGridView.OnCurrentCellDirtyStateChanged(EventArgs e)
場所 System.Windows.Forms.DataGridView.set_IsCurrentCellDirtyInternal(Boolean value)
場所 System.Windows.Forms.DataGridView.NotifyCurrentCellDirty(Boolean dirty)
場所 System.Windows.Forms.DataGridViewTextBoxEditingControl.OnTextChanged(EventArgs e)
場所 System.Windows.Forms.TextBoxBase.WmReflectCommand(Message& m)
場所 System.Windows.Forms.TextBoxBase.WndProc(Message& m)
場所 System.Windows.Forms.TextBox.WndProc(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
場所 System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
場所 System.Windows.Forms.Control.WmCommand(Message& m)
場所 System.Windows.Forms.Control.WndProc(Message& m)
場所 System.Windows.Forms.ScrollableControl.WndProc(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
場所 System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
場所 System.Windows.Forms.Control.DefWndProc(Message& m)
場所 System.Windows.Forms.Control.WmKeyChar(Message& m)
場所 System.Windows.Forms.Control.WndProc(Message& m)
場所 System.Windows.Forms.TextBoxBase.WndProc(Message& m)
場所 System.Windows.Forms.TextBox.WndProc(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
場所 System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.DataGridView.ProcessKeyEventArgs(Message& m)
場所 System.Windows.Forms.Control.ProcessKeyMessage(Message& m)
場所 System.Windows.Forms.Control.WmKeyChar(Message& m)
場所 System.Windows.Forms.Control.WndProc(Message& m)
場所 System.Windows.Forms.DataGridView.WndProc(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
場所 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
場所 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
場所 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
場所 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
場所 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
場所 System.Windows.Forms.Application.Run(ApplicationContext context)
場所 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
場所 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
場所 Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
場所 DataBaseアプリテスト3.My.MyApplication.Main(String[] Args) 場所 17d14f5c-a337-4978-8281-53493378c1071.vb:行 81
場所 System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
場所 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
場所 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
場所 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
場所 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
場所 System.Threading.ThreadHelper.ThreadStart()

なお、このとき、親データテーブル(注文レコード)の保存は行っておりませんが、親データテーブル(注文レコード)の各列データは、他のレコードと同じように入力しているため、各列データを個別に見たときは入力規則から外れているようなことはないはずです。(Ship Via、Freight には数値を入力し、その他も他レコードに習って内容を埋めています。) また、親データテーブル(注文レコード)は既存のもの(プログラム開始時にデータベースから取得したレコード)を使い、子データテーブルの注文明細レコードのみを追加する場合は、問題なく追加できます。

上記エラーの原因について調べたのですが、ネット上に有効な情報が見つかりませんでした。どなたか、わかる方いらっしゃいましたらご指導お願いできませんでしょうかm(。_。)m
ちなみに、親データテーブル(注文レコード)を新規作成した直後、明細レコードを入力する前にセーブ(注文レコードをデータベースへ反映)しようとすると、以下のエラーが発生します。

「 INSERT ステートメントは FOREIGN KEY 制約 "FK_Orders_Shippers" と競合しています。競合が発生したのは、データベース "2CC2523D0155EB8C88B59653F8365310_2005\MYVB2005\WINDOWSアプリテスト\データベースアプリテスト\DATABASEアプリテスト3\DATABASEアプリテスト3\BIN\DEBUG\NORTHWND.MDF"、テーブル "dbo.Shippers", column 'ShipperID' です。ステートメントは終了されました。」

あくまでも冒頭にて紹介しました @IT の連載記事の通りに進めたので、Shippers というテーブルはデータセットに追加していません。このエラーは、連載記事のページ内にある「次ページへ」のリンク(つまり次回の解説)にて、解決される問題だと思い、今回は重視していません。親データテーブル(注文データテーブル)へレコードを追加する場合、外部キー制約のため、最初に親データテーブルのレコードを追加し、その後、子データテーブルのレコードを追加するという順番にする、というのが今後の課題ですが、今回はまだそのようにしておらず、一括で親テーブルのテーブルアダプタの Update を呼び出しているのみです。今回は、セーブをする以前に、親データテーブル内に新規作成したレコードに、明細レコードを追加しようとするとエラーが発生するため困っております。


また、子データテーブル(注文明細レコード)にバインドしているデータグリッド上では、子データテーブルの ProductID 列をキーとして商品マスタから ProductName を取得して ComboBox セルを作っています。(連載記事の解説の通りに行っています。)

DOBON.NET | プログラミング道 | プログラミング掲示板