none
リレーションシップの関係にあるデータを更新するには RRS feed

  • 質問

  • このページを参考にしています。

    http://www.atmarkit.co.jp/fdotnet/special/win20review02/win20review02_01.html

     

    親テーブル は、上のページにあるテーブルとし、

    子テーブルを親テーブルのIDでつながったリレーションシップ(1対多)の関係にあります。

    子テーブル :

    • 子ID : 主キー
    • ID : 親のIDと同じ名前で、親と繋がっている

    • memo : メモ書き

    抱えている問題点

    同じForm上に親テーブルを設置し、次に子テーブルを設置しました。それぞれのテーブルを更新しようとしていますが、小テーブルだけが更新できません。

    どの様にしたら、二つのテーブルを更新できますか。

    2011年3月29日 8:15

回答

  • おおよそは以下のようにすれば良いでしょう。

    親テーブルの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/

    2011年3月29日 15:10
    モデレータ
  • 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
    2011年3月31日 1:21
    モデレータ

すべての返信

  • おおよそは以下のようにすれば良いでしょう。

    親テーブルの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/

    2011年3月29日 15:10
    モデレータ
  • 元の質問が、画面にこだわった質問に読み取れましたが、聞きたい部分はデータベースの更新方法で、画面が無関係なようにも読み取れました。どっちなんでしょうね。

    データベースですが、連鎖参照整合性制約というものがあります。親テーブルの値をUPDATEするとそれに連鎖して、子テーブルの値も同時にUPDATEされる仕組みです。

    2011年3月30日 0:09
  • >親テーブルの値をUPDATEするとそれに連鎖して、子テーブルの値も同時にUPDATEされる仕組みです。

    そうですよね。

    しかし、実際に作ってみるとUPDATEされていない。

    何故なんだろう・・・。

    2011年3月30日 0:25
  • 貼られているURLのページを読みましたが、連鎖参照整合性制約の指定はありませんでしたよ?

    それとも独自に指定されたのでしょうか? もしそうなら質問文に差分として明記してください。

    2011年3月30日 0:27
  • しかし、実際に作ってみるとUPDATEされていない。

    本当に連鎖参照整合性制約や参照整合性制約を理解されていますか??? たぶん、行っていないので親のキーのみ変更されてしまうのだと思いますが・・・。
    連鎖参照整合性制約はキーや外部キーに関してのことになりますが、そうではなくて親テーブル、子テーブルのキー以外の値を変更されたいのでしょうか? 私が最初にご質問内容から受けた印象ですと、親テーブルの誕生日などの変更と同時に子テーブルのmemoの内容も変更したいように受け取れました。(親テーブルの新規追加と同時に子テーブルの新規追加の方が複雑なので、私の最初の回答は新規追加のパターンを説明しています)

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年3月30日 1:04
    モデレータ
  • 言葉足らずで済みません。

    URLのページに、質問文の子テーブルを追加しました。

    2011年3月30日 7:27
  • >本当に連鎖参照整合性制約や参照整合性制約を理解されていますか???

    動いていないので、理解出来ていないということでしょう。・・・多分。

    >親テーブルの誕生日などの変更と同時に子テーブルのmemoの内容も変更したいように受け取れました。

    更新パターンとして、4通りあると思います。

    1. 親テーブルの新規追加と同時に子テーブルの新規追加
    2. 親テーブルの新規追加、子テーブルの据え置き
    3. 親テーブルは据え置き、子テーブルの新規追加
    4. 親テーブル、子テーブルともに据え置き

    >親テーブルの新規追加と同時に子テーブルの新規追加の方が複雑なので、私の最初の回答は新規追加のパターンを説明しています

    有難うございます。

    動作テストをしながら勉強をさせていただきます。

    2011年3月30日 7:50
  • 子テーブルを追加されたことは元の質問文からもわかるのですが、追加された後に子テーブルのみが更新されないというのは、具体的にどのような操作をされているのでしょうか? 一般的なシナリオですと私が前述した通りだと思うのですが、どのようなシナリオなのでしょうか?

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年3月30日 7:53
    モデレータ
  • 教えて頂いたURLを参照に作ってみたいと思います。

    ありがとうございます。

    2011年3月30日 7:54
  • 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」に変わりました。

    データベースに登録されたのであろと思い、アプリを終了してデータベースエクスプローラでデータの値を確認してみると更新されていません。アプリをもう一度、起動してみても同じでした。

     

    以上、シナリオと言えるかどうか判りませせんが、今、かかえている問題点を上げておきます。

    2011年3月31日 1: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
    2011年3月31日 1:21
    モデレータ
  • ありがとうございます

    ようやく、解決できました。

    しかし、データベースをローカルにコピーするというのは、混乱を招きますね。

    2011年3月31日 2:08