none
【C#】 接続データベースの親テーブルと子テーブルの同時更新について RRS feed

  • 質問

  • お世話になります。

    下記の記事を参考にさせていただきながらC#にて
    IDをキーにリレーションを設定した親テーブルと子テーブルを利用した
    編集画面の作成を致しました。

    ・10 行でズバリ !! 非接続型のデータ アクセス (ADO.NET) (C#)
     (リンクが貼れないので題名のみで申し訳ありません)

    新規入力時、親テーブルと子テーブルの同時更新が上手くいかず、
    回避方法をお教えいただきたくご質問させていただきました。

    【環境】
    C#のバージョン:visual studio 2017
    ・接続データベース:Access2003 SP3

    【入力手順】

    1. 作成した入力画面で親テーブルの情報を入力しました。
      IDAccess上オートナンバー型ですが、表示上は-1となっておりました。
    2. 次に子テーブルの情報を入力したところ、
      IDは親テーブルと同じように-1となっておりました。
      差し当たり、そのまま保存ボタンを押して閉じてみました。
    3. 再度入力画面を開いて入力したデータを確認したところ、
      親テーブルの
      IDは表示されていた-1ではなく、
      オートナンバーで採番されたと思われる最終番号(仮に
      100)が
      採番されており、子テーブルのデータは消えておりました。
    4. ID:100の親テーブルの情報に対し、子テーブルに情報を再度入力しますと、
      子テーブルの
      ID100となり、こちらを保存して閉じてみますと
      今度は保存されました。

    親テーブルと子テーブルを同時更新される方法を
    ご教示いただきたいと思っております。よろしくお願い致します。

    2018年5月23日 8:31

回答

  • Access で利用している JET / ACE データベースエンジンでは、単一バッチで複数のステートメントを実行できないという問題があります。

    なので、データベース構成ウィザードが生成するコードでは、Access でオートナンバーを使っている場合、INSERT した時に DB 側で設定したオートナンバー値を DataSet に書き込むところまでは面倒を見てくれません。

    そのあたりが原因ではないかと思われます。(思うだけで未検証・未確認ですが)

    DB 側で設定したオートナンバー値を DataSet に書き込むのは、単一テーブルが対象の場合は以下の記事に書いてある方法で対応できます。

    Access の更新
    http://surferonwww.info/BlogEngine/post/2010/09/04/Updating-Access.aspx

    上の記事のようにして、 2 つのテーブルを階層更新するような質問者さんのケースに対応できるかどうかは分かりませんので、ご参考までにとどめておいてください。

    SQL Server を使えないのですか? それができれば一番簡単かつ確実な解決方法なのですが。

    #上に紹介した記事からリンクが張ってある Microsoft の記事では Access は「おもちゃのデータベース エンジン」とか言われてますし。



    • 編集済み SurferOnWww 2018年5月23日 9:01 訂正追加
    • 回答としてマーク sasatomo 2018年5月30日 3:38
    2018年5月23日 8:54
  • 親テーブルと子テーブルにリレーションがあれば、子テーブルのIDは親テーブルのIDで自動的に更新されます。
    詳しくは以下をご覧下さい。

    第7回 マスタ/詳細テーブルにおける更新処理
    www.atmarkit.co.jp/ait/articles/0711/27/news121.html


    コードでもリレーションを設定することができます。

    10 行でズバリ !! リレーショナルデータテーブルの構築 (C#)
    https://code.msdn.microsoft.com/windowsdesktop/10-C-3ca2d03e

    (参考)
    リレーションを設定せずに行うこともできます。その場合、親テーブルのRowUpdatedイベントで実際にデータベースで採番されたID値を取得できますので、それを子テーブルのIDにセットして、子テーブルも更新するという流れになります。当然ですが、親テーブルと子テーブルの更新は1つのトランザクション内で行って下さい。

    (追記)
    Accessでしたね。SurferOnWwwさんが書かれているように、Accessの場合、RowUpdatedイベントハンドラで上記のことを行うしかありません。


    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    2018年5月23日 8:56
    モデレータ
  • > 作成したpartial class中の” Adapter”と、読み込ませるフォームの”InitializeComponent();”の下に記載した”SetHandler”の部分に赤波線がついてしまい、原因を探しております。

    それは多分「作成したpartial class」に質問者さんが書いたコードで名前空間が間違っているからでしょう。

    ひょっとして、先に紹介した記事(URL 下記に再掲)のコードをそのままコピペしてませんか?

    Access の更新
    http://surferonwww.info/BlogEngine/post/2010/09/04/Updating-Access.aspx

    それではダメです。質問者さんがウィザードで自動生成させたコードを見て、それに合わせないと。

    名前空間は .xsd ファイルの下に .Designer.cs というファイルがあるはずなのでそれを開いて調べてください。

    上の記事の場合は以下の画像の通りです。

    • 回答としてマーク sasatomo 2018年5月30日 3:37
    2018年5月25日 0:57
  • > お教えいただいた記事を差し当たりはコピーし貼り付けし、ご指摘のあったnamespaceの名称とTableAdapterの名称は合わせております。

    いや、合ってないと思いますよ。一字一句、大文字小文字、全角半角など違いがないかよく見てください。

    例えば、紹介した記事の例でも、以下のように AccessWith... の W を小文字にすると Adpater に赤い波線が付きます。同じ状況ですよね?

    赤い波線が出るという Adapter というのは自動生成された TableAdapter に定義されているプロパティです。名前空間と partial 定義したクラス名が合っていれば間違いなく認識されて赤い線は出るはずはないです。

    コピペだけではダメです。コピペするのはやむを得ないとしても何をしているかを理解するのは重要です。勉強してください。でないと、いつまでたっても同じことの繰り返しです。

    • 回答としてマーク sasatomo 2018年5月30日 3:37
    2018年5月25日 5:55
  • 赤破線にマウスポインターを持って行った時に、何と表示されますでしょうか?
    つまり、エラーは何というエラーメッセージが出ているのでしょうか?
    回答者にとってエラーメッセージは重要です。必ず記載するようにお願いいたします。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    • 回答としてマーク sasatomo 2018年5月30日 3:37
    2018年5月25日 5:41
    モデレータ

すべての返信

  • Access で利用している JET / ACE データベースエンジンでは、単一バッチで複数のステートメントを実行できないという問題があります。

    なので、データベース構成ウィザードが生成するコードでは、Access でオートナンバーを使っている場合、INSERT した時に DB 側で設定したオートナンバー値を DataSet に書き込むところまでは面倒を見てくれません。

    そのあたりが原因ではないかと思われます。(思うだけで未検証・未確認ですが)

    DB 側で設定したオートナンバー値を DataSet に書き込むのは、単一テーブルが対象の場合は以下の記事に書いてある方法で対応できます。

    Access の更新
    http://surferonwww.info/BlogEngine/post/2010/09/04/Updating-Access.aspx

    上の記事のようにして、 2 つのテーブルを階層更新するような質問者さんのケースに対応できるかどうかは分かりませんので、ご参考までにとどめておいてください。

    SQL Server を使えないのですか? それができれば一番簡単かつ確実な解決方法なのですが。

    #上に紹介した記事からリンクが張ってある Microsoft の記事では Access は「おもちゃのデータベース エンジン」とか言われてますし。



    • 編集済み SurferOnWww 2018年5月23日 9:01 訂正追加
    • 回答としてマーク sasatomo 2018年5月30日 3:38
    2018年5月23日 8:54
  • 親テーブルと子テーブルにリレーションがあれば、子テーブルのIDは親テーブルのIDで自動的に更新されます。
    詳しくは以下をご覧下さい。

    第7回 マスタ/詳細テーブルにおける更新処理
    www.atmarkit.co.jp/ait/articles/0711/27/news121.html


    コードでもリレーションを設定することができます。

    10 行でズバリ !! リレーショナルデータテーブルの構築 (C#)
    https://code.msdn.microsoft.com/windowsdesktop/10-C-3ca2d03e

    (参考)
    リレーションを設定せずに行うこともできます。その場合、親テーブルのRowUpdatedイベントで実際にデータベースで採番されたID値を取得できますので、それを子テーブルのIDにセットして、子テーブルも更新するという流れになります。当然ですが、親テーブルと子テーブルの更新は1つのトランザクション内で行って下さい。

    (追記)
    Accessでしたね。SurferOnWwwさんが書かれているように、Accessの場合、RowUpdatedイベントハンドラで上記のことを行うしかありません。


    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    2018年5月23日 8:56
    モデレータ
  • SurferOnWww

    記事の紹介をありがとうございました。
    同時更新出来ない理由が分かり、紹介いただいた記事を参考にしながら
    作成し検証しておりますがまだ上手く動かない状況です。

    作成したpartial class中の Adapterと、読み込ませるフォームのInitializeComponent();”の下に記載した”SetHandler”の部分に
    赤波線がついてしまい、原因を探しております。
    もう少し自身で原因を探ろうと思っております。
    またお聞きするかもしれませんが申し訳ありません。

    SQL Serverでの運用について上司に相談しておりますが、
    私自身が事務員レベルで
    Accessを使ってきたため、
    差し当たり表面的に
    Visual studioで接続してデータをやりとりするPGを作成してみて欲しいとのことで、今のところこのまま
    Accessで進めております。

    ですが私自身、ゆくゆくはSQL Serverを学習し、
    運用出来るようにしたいと考えております。
    いつもありがとうございます。

    2018年5月24日 8:22
  • trapemiya

    記事の紹介をありがとうございました。

    記事を読むとやはりSQL Serverですと
    解決に近づけそうな印象なのですが、
    差し当たりAccessで、
    RowUpdatedのイベントでやってみようと思います。
    またお聞きするかもしれませんが申し訳ありません。
    いつもありがとうございます。

    2018年5月24日 8:24
  • > 作成したpartial class中の” Adapter”と、読み込ませるフォームの”InitializeComponent();”の下に記載した”SetHandler”の部分に赤波線がついてしまい、原因を探しております。

    それは多分「作成したpartial class」に質問者さんが書いたコードで名前空間が間違っているからでしょう。

    ひょっとして、先に紹介した記事(URL 下記に再掲)のコードをそのままコピペしてませんか?

    Access の更新
    http://surferonwww.info/BlogEngine/post/2010/09/04/Updating-Access.aspx

    それではダメです。質問者さんがウィザードで自動生成させたコードを見て、それに合わせないと。

    名前空間は .xsd ファイルの下に .Designer.cs というファイルがあるはずなのでそれを開いて調べてください。

    上の記事の場合は以下の画像の通りです。

    • 回答としてマーク sasatomo 2018年5月30日 3:37
    2018年5月25日 0:57
  • SuferOnWww様

    お忙しいところありがとうございました。

    行ったことは[ソリューションエクスプローラー]より[追加]-[新しい項目]Classを追加し、
    お教えいただいた記事を差し当たりはコピーし貼り付けし、ご指摘のあった
    namespaceの名称とTableAdapterの名称は合わせております。他、キーとなる”ID”もこちらでは伝票番号
    なりますのでそのように修正しておりますが、やはり先に投稿した
    2箇所の赤波線のエラーとなります。

    partial classの追加方法が間違っているのでしょうか。
    何かお気づきの点などありましたらお教えいただきたいと思っております。
    いつもありがとうございます。

    2018年5月25日 5:16
  • 赤破線にマウスポインターを持って行った時に、何と表示されますでしょうか?
    つまり、エラーは何というエラーメッセージが出ているのでしょうか?
    回答者にとってエラーメッセージは重要です。必ず記載するようにお願いいたします。

    ★良い回答には質問者は回答済みマークを、閲覧者は投票を!

    • 回答としてマーク sasatomo 2018年5月30日 3:37
    2018年5月25日 5:41
    モデレータ
  • > お教えいただいた記事を差し当たりはコピーし貼り付けし、ご指摘のあったnamespaceの名称とTableAdapterの名称は合わせております。

    いや、合ってないと思いますよ。一字一句、大文字小文字、全角半角など違いがないかよく見てください。

    例えば、紹介した記事の例でも、以下のように AccessWith... の W を小文字にすると Adpater に赤い波線が付きます。同じ状況ですよね?

    赤い波線が出るという Adapter というのは自動生成された TableAdapter に定義されているプロパティです。名前空間と partial 定義したクラス名が合っていれば間違いなく認識されて赤い線は出るはずはないです。

    コピペだけではダメです。コピペするのはやむを得ないとしても何をしているかを理解するのは重要です。勉強してください。でないと、いつまでたっても同じことの繰り返しです。

    • 回答としてマーク sasatomo 2018年5月30日 3:37
    2018年5月25日 5:55
  • trapemiya様

    エラー内容を記載せず、大変失礼致しました、申し訳ありませんでした。
    エラー内容を下記に記載致しました。

    [Adapter に対するエラー]

    ○○○TableAdapter’Adapter’の定義が含まれておらず、
    ○○○TableAdapter’の最初の引数を受け付ける
    拡張メソッド
    ’Adapter’が見つかりませんでした。
    Using ディレクトリまたはアセンブリ参照が不足していないことを確認して下さい。

    [SetHandler に対するエラー]

    ○○○TableAdapter’ SetHandler’の定義が含まれておらず、
    ○○○TableAdapter’の最初の引数を受け付ける
    拡張メソッド
    ’SetHandler’が見つかりませんでした。
    Using ディレクトリまたはアセンブリ参照が不足していないことを確認して下さい。

    2018年5月25日 6:29
  • SurferOnWww

    慎重に見て追っていったつもりですが
    慣れずに大変申し訳ありませんでした。
    もう一度よく自身で確認致します。

    2018年5月25日 6:30
  • SurferOnWww

    詳しい解説のおかげで解決出来ました、ありがとうございました。
    私のnamespaceの定義が間違っておりました。
    やはりまだ慣れないせいか思いこみや勘違いがあり、
    何度もやり直しやっと解決しました。
    学習の仕方が難しいですが頑張っていきたいと思います。
    ありがとうございました。

    2018年5月30日 3:37