Access (一般機能)

Accessの一般機能に関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : 指定なし)
サブフォームでの編集内容のキャンセル方法
投稿日時: 21/06/11 16:36:50
投稿者: だいふくもち

こちらのコミュニティにはいつも大変お世話になっております。
現在作成しているものがあるのですが、行き詰まってしまった部分があり
どなたかご経験者様のお知恵をお借りしたく質問させていただきました。
 
さっそくですが、質問の内容に入らせていただきます。
過去に登録したデータを編集する際は、
@検索用フォーム(帳票形式)から編集したいレコードのレコードセレクタをダブルクリック
A編集用フォーム(単票形式)を開き、選択したレコードまでジャンプする
B編集したい項目を修正し、登録ボタン(コマンドボタン)を押す
もしくはキャンセルボタン(コマンドボタン)を押して編集を破棄する
以上の流れで編集を行っております。
 
以下、問題のある箇所についてです。
編集用フォームにはサブフォームが2つ埋め込まれているのですが、
サブフォームの情報を編集してから、キャンセルボタンを押しても
キャンセルしたはずの編集内容がテーブルに登録されてしまいます。
 
調べると、メインフォームからサブフォームにフォーカスが移ると
自動的にサブフォームの内容が保存されてしまう…とありました。
サブフォームの編集内容を取り消すには、どのようにすればよろしいか
もしご存じの方がいらっしゃいましたら教えていただけませんでしょうか…?
 
以下、具体的な構成です。
 
【編集用フォームのレコードソース】
編集用フォーム=T_契約マスタ(主キー:契約番号)
サブフォーム1=T_金額マスタ(リンク親子フィールド:契約番号)
サブフォーム2=T_請求書作成マスタ(リンク親子フィールド:契約番号)
 
【「編集キャンセルボタン」コマンドに登録しているマクロ】

'元に戻すコマンドが使えない状況のときは無視
On Error Resume Next
'「レコード削除」のメッセージを非表示にする
DoCmd.SetWarnings False
'メインフォームの編集内容をキャンセルする
DoCmd.RunCommand acCmdUndo '元に戻すコマンドを実行
'サブフォーム1の編集内容をキャンセルする
Me!S_サブフォーム1.SetFocus
DoCmd.RunCommand acCmdUndo
'サブフォーム2の編集内容をキャンセルする場合
Me!S_サブフォーム2.SetFocus
DoCmd.RunCommand acCmdUndo
'「レコード削除」のメッセージを再表示にする
DoCmd.SetWarnings True

以上を使用すると、ひとつ前の内容だったら消すことができました。(ctrl+Zキーと同じ機能)
 
【思いついた案】
サブフォームでの編集は諦めて、各テーブルのフォームを作成し、個別で編集する
 
ここまで見てくださってありがとうございました!

回答
投稿日時: 21/06/11 17:34:19
投稿者: Suzu

手法としてはいくつかあります。
 
 
手法 1
 レコードソースとなる テーブルをメイン/サブ分を複製(レコードは空で良い)
 フォームのレコードソースを、複製したテーブルとする。
 
 検索用フォームにて編集したいレコードを選択した際に
 複製したテーブルに、当該レコードを追加クエリにて追加(サブフォーム分も追加)
 編集後、登録ボタンにより、本来のテーブルのレコードを削除し、複製テーブルから追加クエリにて追加
 複製テーブルのレコードを削除
 
メリット  : 構成する為のスキルとしては、他の方法に比べて低い
 
デメリット : 保存テーブルと別のテーブルで編集となるので、レコードロック機能
        (複数人にて、同一レコード(周辺)のレコードに対し 編集できない様にする機能)
        を使う場合には、その仕組みを自前で用意する必要がある。
 
 
 
 
手法 2
 非連結フォームに、
 入力フィールド分の、コントロールを 非連結コントロールとして配置
 サブフォーム分も、非連結コントロールとして、 フィールド数 * レコード数分を配置
 
 レコードセットとして編集したいレコードを取得し、コントロール上に配置
 保存ボタンにより、レコードセット経由にて、レコード保存
 
 
メリット  : テーブルを増やす必要がない
        レコードセットにて、レコードロックを掛ける事が可能
 
 
デメリット : レコードセットにて操作が必要。
        Accessのフォームを使うメリットが無い
        エラーや停電が発生した場合、データの整合性の確認が必要
 
 
 
手法 3
 フォームを開いた後 ​フォームのレコードセットプロパティーを取得。
 
 上位のオブジェクトに対し、トランザクションを適用。
 登録時に、コミット処理を実行
 
 
メリット  : コミットを行うまで、レコードは保存されない。
        トラブルが発生しても、自動で元に戻る
 
デメリット : 必要スキルが高い。
 
 
ネットワーク経由にて、複数同時使用 の場合には
ロックの考え方や、ネットワーク速度や、遅延 はじめ、いろいろな検討が必要になります。
 
 
Accessで、バランスが取れると思うのは 手法2でしょうかね。。
でも、その考え方なら、フォームはExcelのフォームを使ってもなので。。

回答
投稿日時: 21/06/11 17:41:28
投稿者: hatena
投稿者のウェブサイトに移動

メインフォームとサブフォームのデータの関係は一対多ということですよね。
で、メインフォームでキャンセルを押したら、サブの複数レコードも元に戻したいということでしょうか。
 
だとしたら、
 

引用:
サブフォームでの編集は諦めて、各テーブルのフォームを作成し、個別で編集する

 
としても一つ前(1レコードのみ)しか戻すことはできません。
 
サブフォームには一時テーブルと連結させて、メインフォームと紐づくデータを一時テーブルに追加して、入力後元テーブルに戻すような設計にします。
そうすれば、キャンセルボタンを押したときは、メインフォームのみ元に戻せばOKになります。
 

投稿日時: 21/06/14 11:02:06
投稿者: だいふくもち

>Suzu様
ご回答いただきありがとうございます!
そしてお礼の返信が遅くなってしまい、大変申し訳ありません…
案を3つも…!メリット/デメリットを添えて
分かりやすく教えていただき本当に感謝しかありません!
 
教えていただいたいずれかの案で検討しようかと思うのですが、
手法1の工程の中で、一か所分からない点がありまして…
 

検索用フォームにて編集したいレコードを選択した際に
 複製したテーブルに、当該レコードを追加クエリにて追加(サブフォーム分も追加)

この場合、アクションクエリもしくはSQL文で処理することになるかと思われるのですが、
アクションクエリを作成する場合、検索用フォームで選択したレコードの値を
どのようにアクションクエリに反映するのか、どうしてもやり方が分かりません…
このような場合、SQL文で追加クエリを作成しWHERE句で条件を書くのが主流なのでしょうか?
 
手法2に関しても、具体的な作り方が少し難しかったので
調べてみたのですが、以下のサイトを参考にしてみようと思います。
http://accessvba.pc-users.net/ado/update.html
 
手法3に関しては…もっと勉強してから検討したいと思います!

投稿日時: 21/06/14 11:07:23
投稿者: だいふくもち

>hatena様
以前hatena様に助けていただいたことのある者です。
今回もご教授いただき本当にありがとうございます…!
 

メインフォームとサブフォームのデータの関係は一対多ということですよね。
で、メインフォームでキャンセルを押したら、サブの複数レコードも元に戻したいということでしょうか。

そうです!伝わりづらい文章で申し訳ありません…
 
別々に編集したとしても、キャンセルは難しいのですね…
とても参考になりました。仮テーブルを使用する方法も検討したいと思います。
ご回答いただきありがとうございました!

回答
投稿日時: 21/06/14 14:52:18
投稿者: Suzu

引用:
この場合、アクションクエリもしくはSQL文で処理することになるかと思われるのですが、
アクションクエリを作成する場合、検索用フォームで選択したレコードの値を
どのようにアクションクエリに反映するのか、どうしてもやり方が分かりません…
このような場合、SQL文で追加クエリを作成しWHERE句で条件を書くのが主流なのでしょうか?
アクションクエリの 主キーとなるフィールドの抽出条件に
[Forms]![検索用フォーム]![レコードの主キーとなるフィールドに連結したコントロール名]
の様にすれば、検索用フォームにて選択したレコードのコントロールの値が抽出条件となります。
 
引用:
手法2に関しても、具体的な作り方が少し難しかったので
調べてみたのですが、以下のサイトを参考にしてみようと思います。
http://accessvba.pc-users.net/ado/update.html
 
手法3に関しては…もっと勉強してから検討したいと思います!

 
方法論としては、存在します。
でも、
・カーソルが別レコードに移動する前
・フォームが閉じる前
に、そのレコードの変更内容がテーブルに反映する。
これは、Accessの仕様なのです。 保存を 意図させる必要がない。
 
それを、覆そうとするのですから、面倒で当然です。
 
 
敢えてスルーされているのか判りませんが
引用:
ネットワーク経由にて、複数同時使用 の場合には
ロックの考え方や、ネットワーク速度や、遅延 はじめ、いろいろな検討が必要になります。
があります。
 
3つの方法は、どれを採るにしても、初めはドツボにはまると思います。
その覚悟だけはしておいてください。
 
逆に言うと、これが実装できたなら、Access 上級者と言っても良いかと思います。
 
 
 
あ。。もう一個だけ方法が無い事も無いですが。。
サブフォームの 1レコード事に 「保存」ボタンを押して良いなら。。。
 
サブフォームのどこかに 「保存」ボタンを配置。
保存ボタンを押した時に、変数に True を渡し、
フォームの 更新前処理にて、変数を参照させます。
  変数が False の場合には、Cancel を行い、保存できない様にします。
 
保存 を押さないと保存できない様にしてしまう方法です。
 
レコード事になので。。サブフォーム構成には向かないですね。
 
 
参考コード(動作確認していません。)
'モジュールレベル変数
Private bln_Save As Boolean

Private Sub 保存_Click()
  bln_Save =True
End Sub

Private Sub Form_BeforeUpdate(Cancel As Integer) 
  If bln_Save = True Then
  Else
    Cancel = True
  End If
End Sub

Private Sub Form_Current()
  bln_Save =False
End Sub

 
上記のみの場合、保存できない場合、Current イベントが発生しません。
つまり、フォームを閉じる事もできなくなります。
フォームを閉じる時にも、bln_Save を True にする必要があります。

投稿日時: 21/06/16 12:09:14
投稿者: だいふくもち

>Suzu様
ご丁寧かつ分かりやすく教えていただきありがとうございました!
 

引用:
アクションクエリの 主キーとなるフィールドの抽出条件に
[Forms]![検索用フォーム]![レコードの主キーとなるフィールドに連結したコントロール名]
の様にすれば、検索用フォームにて選択したレコードのコントロールの値が抽出条件となります。

こちらの方法でやってみたところ、無事できました!ありがとうございます!
 
小さい部署ですので、共用のPCで使用する予定だったため
ロック機能などはそれほど気にしなくてもいいのかな、と当初は思っていたのですが、
もし使用する人が増えた場合など、ネットワークを通じて
同時使用しなければならない場合を考えて作るべきなんだろうな…と思い始めました。
そこあたりの知識がまだ乏しいので、まずは似たような事例を調べてみようと思います!
また、新たな手法4に関してもご提案いただきありがとうございました!
 
Suzu様のように問題にぶち当たってもアイデアを形にできる技量を持ち
メリット・デメリットを比較できるようになりたいものです…
重ねてになりますが、この度は助けていただき本当にありがとうございました!