トップ回答者
リレーションシップの関係にあるデータを更新するには

質問
-
このページを参考にしています。
http://www.atmarkit.co.jp/fdotnet/special/win20review02/win20review02_01.html
親テーブル は、上のページにあるテーブルとし、
子テーブルを親テーブルのIDでつながったリレーションシップ(1対多)の関係にあります。
子テーブル :
- 子ID : 主キー
-
ID : 親のIDと同じ名前で、親と繋がっている
-
memo : メモ書き
抱えている問題点
同じForm上に親テーブルを設置し、次に子テーブルを設置しました。それぞれのテーブルを更新しようとしていますが、小テーブルだけが更新できません。
どの様にしたら、二つのテーブルを更新できますか。
回答
-
おおよそは以下のようにすれば良いでしょう。
親テーブルのID値はデフォルトで-1, -2, -3,・・・と追加する度に負の方向に値が割り当てられているはずです。この負のID値で子テーブルのIDもセットしておきます。もちろんリレーションがあるものとします。
この状態で親テーブルに対応するTableAdapterのUpdateメソッドを呼びます。その結果、TableAdapterのInsertCommandのSQLが実行され、SQL Serverで新たにレコードが保存される時に実際のID値が割り当てられます。(もちろんID値は自動インクリメントされる設定にしておきます)
InsertCommandのSQLには続きがあって、Select文が書かれているはずです。このSelect文によってSQL Serverで割り当てられたID値が親テーブルに返されます。この時、子テーブルにリレーションが張ってあるため、子テーブルのID(外部キー)も自動的にその値になります。
例えば、親テーブルのID値が-5であった時に、SQL Serverに保存した後は31などと、SQL Serverにおける実際のID値に置き換えられます。同様にリレーション関係にある子テーブルのID値も31になります。
その後、子テーブルに対するTableAdapterのUpdateメソッドを実行します。
もちろん、親テーブル、子テーブルの更新はトランザクションを切るようにしてください。TransactionScopeを使えば良いでしょう。#追記。良い記事がありました。私が上で述べたことが詳しく書かれています。この連載を読まれると良いでしょう。
連載:Visual Studio 2005によるWindowsデータベース・プログラミング
第7回 マスタ/詳細テーブルにおける更新処理
リレーションシップにおける連鎖更新の必要性
http://www.atmarkit.co.jp/fdotnet/vblab/vsdbprog_07/vsdbprog_07_04.html
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
- 編集済み trapemiyaModerator 2011年3月29日 15:40 追記
- 回答としてマーク taokato 2011年3月31日 2:08
-
IDの値がプラス値に変化しているので、データベースで保存されてID値が裁番されたように思われます。それでも更新されていないのでしたら、更新されていないデータベースを見ているのかもしれません。
データベースは何をどのようにお使いでしょうか? とりあえずデータベースファイルだと仮定して、以下をご紹介しておきます。VB Expressでmdf(SQL)ファイルに保存できない・・・
http://social.msdn.microsoft.com/Forums/ja-JP/vbexpressja/thread/b2e01e8b-ed79-4c23-8ffa-9eb8daa23092
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク taokato 2011年3月31日 2:08
すべての返信
-
おおよそは以下のようにすれば良いでしょう。
親テーブルのID値はデフォルトで-1, -2, -3,・・・と追加する度に負の方向に値が割り当てられているはずです。この負のID値で子テーブルのIDもセットしておきます。もちろんリレーションがあるものとします。
この状態で親テーブルに対応するTableAdapterのUpdateメソッドを呼びます。その結果、TableAdapterのInsertCommandのSQLが実行され、SQL Serverで新たにレコードが保存される時に実際のID値が割り当てられます。(もちろんID値は自動インクリメントされる設定にしておきます)
InsertCommandのSQLには続きがあって、Select文が書かれているはずです。このSelect文によってSQL Serverで割り当てられたID値が親テーブルに返されます。この時、子テーブルにリレーションが張ってあるため、子テーブルのID(外部キー)も自動的にその値になります。
例えば、親テーブルのID値が-5であった時に、SQL Serverに保存した後は31などと、SQL Serverにおける実際のID値に置き換えられます。同様にリレーション関係にある子テーブルのID値も31になります。
その後、子テーブルに対するTableAdapterのUpdateメソッドを実行します。
もちろん、親テーブル、子テーブルの更新はトランザクションを切るようにしてください。TransactionScopeを使えば良いでしょう。#追記。良い記事がありました。私が上で述べたことが詳しく書かれています。この連載を読まれると良いでしょう。
連載:Visual Studio 2005によるWindowsデータベース・プログラミング
第7回 マスタ/詳細テーブルにおける更新処理
リレーションシップにおける連鎖更新の必要性
http://www.atmarkit.co.jp/fdotnet/vblab/vsdbprog_07/vsdbprog_07_04.html
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
- 編集済み trapemiyaModerator 2011年3月29日 15:40 追記
- 回答としてマーク taokato 2011年3月31日 2:08
-
しかし、実際に作ってみるとUPDATEされていない。
本当に連鎖参照整合性制約や参照整合性制約を理解されていますか??? たぶん、行っていないので親のキーのみ変更されてしまうのだと思いますが・・・。
連鎖参照整合性制約はキーや外部キーに関してのことになりますが、そうではなくて親テーブル、子テーブルのキー以外の値を変更されたいのでしょうか? 私が最初にご質問内容から受けた印象ですと、親テーブルの誕生日などの変更と同時に子テーブルのmemoの内容も変更したいように受け取れました。(親テーブルの新規追加と同時に子テーブルの新規追加の方が複雑なので、私の最初の回答は新規追加のパターンを説明しています)
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/ -
>本当に連鎖参照整合性制約や参照整合性制約を理解されていますか???
動いていないので、理解出来ていないということでしょう。・・・多分。
>親テーブルの誕生日などの変更と同時に子テーブルのmemoの内容も変更したいように受け取れました。
更新パターンとして、4通りあると思います。
- 親テーブルの新規追加と同時に子テーブルの新規追加
- 親テーブルの新規追加、子テーブルの据え置き
- 親テーブルは据え置き、子テーブルの新規追加
- 親テーブル、子テーブルともに据え置き
>親テーブルの新規追加と同時に子テーブルの新規追加の方が複雑なので、私の最初の回答は新規追加のパターンを説明しています
有難うございます。
動作テストをしながら勉強をさせていただきます。
-
http://www.atmarkit.co.jp/fdotnet/vblab/vsdbprog_07/vsdbprog_07_03.html を参考にプログラムを書いてみました。
セーブアイコンを押下すると、次のコードに入ってきます。
private void customerBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.customerBindingSource.EndEdit();
this.memoBindingSource.EndEdit();DataRow[] rows = null;
// memoテーブルの削除処理
rows = this.customerManagementDataSet.memo.Select("", "", DataViewRowState.Deleted);
if (rows.Length != 0)
{
this.memoTableAdapter.Update(rows);
}// customerテーブルの削除処理
rows = this.customerManagementDataSet.customer.Select("", "", DataViewRowState.Deleted);
if (rows.Length != 0)
{
this.customerTableAdapter.Update(rows);
}// customerテーブルの追加・変更処理
rows = this.customerManagementDataSet.customer.Select("", "", DataViewRowState.Added | DataViewRowState.ModifiedCurrent);
if (rows.Length != 0)
{
this.customerTableAdapter.Update(rows);
}// memoテーブルの追加・変更処理
rows = this.customerManagementDataSet.memo.Select("", "", DataViewRowState.Added | DataViewRowState.ModifiedCurrent);
if (rows.Length != 0)
{
this.memoTableAdapter.Update(rows);
}
}親テーブルは、customer。 子テーブルをmemoとしています。
子テーブルのみを追加しますと、「memoテーブルの追加・変更処理」に入って「this.memoTableAdapter.Update(rows);」の処理を実行します。この時、子テーブルのIDの値が「-1」から「+n」に変わりました。
データベースに登録されたのであろと思い、アプリを終了してデータベースエクスプローラでデータの値を確認してみると更新されていません。アプリをもう一度、起動してみても同じでした。
以上、シナリオと言えるかどうか判りませせんが、今、かかえている問題点を上げておきます。
-
IDの値がプラス値に変化しているので、データベースで保存されてID値が裁番されたように思われます。それでも更新されていないのでしたら、更新されていないデータベースを見ているのかもしれません。
データベースは何をどのようにお使いでしょうか? とりあえずデータベースファイルだと仮定して、以下をご紹介しておきます。VB Expressでmdf(SQL)ファイルに保存できない・・・
http://social.msdn.microsoft.com/Forums/ja-JP/vbexpressja/thread/b2e01e8b-ed79-4c23-8ffa-9eb8daa23092
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/- 回答としてマーク taokato 2011年3月31日 2:08