Access (VBA) |
![]() ![]() |
(Windows 10 Pro : Microsoft 365)
「このコンテキストで操作は許可されていません」とエラーが出る
投稿日時: 22/11/18 11:43:47
投稿者: rose11
|
---|---|
お世話になります。まだまだACCESS初心者です。
|
![]() |
投稿日時: 22/11/18 13:47:38
投稿者: sk
|
---|---|
引用: 一般論としての話なら「場合によるので正解はない」、 例示されたコードに関しての話なら「処理の結果や ロジックに影響しないならどっちでもいい」という 回答になります。 引用: 引用: AddNew メソッドが呼び出された後、その直後のステートメントを 実行しようとした際に実行時エラーが発生したことにより Update メソッドが呼び出されぬままプロシージャを抜け、 更にその状態のまま Close メソッドを呼び出そうとしたためです。 Close メソッド (ADO) : https://learn.microsoft.com/ja-jp/sql/ado/reference/ado-api/close-method-ado?view=sql-server-ver16 Microsoft さんの引用: 引用: コーディング全般の話としてなら、その手の話題は宗教論争になりかねませんので 「とりあえず『リーダブルコード』でも読みなはれ」という提案に留めておきます。 例示されたコードに関して言えば、いくつか修正の余地があるでしょう。 |
![]() |
投稿日時: 22/11/18 15:39:35
投稿者: rose11
|
---|---|
sk 様
引用: ありがとうございます。勉強になりました。 引用: ありがとうございます。理由がよく解りました。 引用: '************************************************************************ Private Sub RegistTest(T_Table As ADODB.Recordset, strEmpCode As String) T_Table.AddNew T_Table.Update T_Table!社員コード = strEmpCode '※2 T_Table.Update End Sub こういうことでしょうか? これでも同じエラーが出るので、解釈が違うでしょうか。 引用: ご教示ありがとうございます! 引用: 自分なりに考えた修正箇所は例えば、 ・「Private Sub RegistTest・・・」にもエラー処理を施す ・「Private Sub RegistTest(T_Table As ADODB.Recordset, strEmpCode As String)」 を 「Private Function RegistTest(T_Table As ADODB.Recordset, strEmpCode As String) as Boolean」 にして、呼び出し元は If RegistTest(rst, rs!社員コード.Value) = False Then strErrorMsg="エラー:RegistTest" : GoTo catchError にする、でした。 もしよろしければ修正箇所のヒントをご教示いただけますと幸いです。 重ね重ねお世話をおかけします。 どうぞよろしくお願いいたします。 |
![]() |
投稿日時: 22/11/18 18:14:41
投稿者: sk
|
---|---|
引用: その Update メソッドはむしろ余計です。 とりあえず、標準モジュールに次のようなプロシージャを追加して下さい。 (標準モジュール) ------------------------------------------------------------ 'レコードセットの解放をより細かく行なうサブルーチン(あくまでサンプル) Sub ReleaseRecordset(Recordset As ADODB.Recordset) 'オブジェクトを参照していなければ If Recordset Is Nothing Then 'プロシージャを抜ける Exit Sub End If With Recordset 'レコードセットが開かれている場合 If .State = adStateOpen Then '新規レコードが挿入されたか、カレントレコードの編集中である場合 If .EditMode And (adEditAdd + adEditInProgress) <> 0 Then '変更を全てキャンセルする .CancelUpdate End If 'レコードセットを閉じる .Close End If End With '参照を解放 Set Recordset = Nothing End Sub ------------------------------------------------------------ 引用: そして上記のステートメントを次のように書き換えてみて下さい。 ------------------------------------------------------------ EndProc: Call ReleaseRecordset(rs) Call ReleaseRecordset(rst) ------------------------------------------------------------ |
![]() |
投稿日時: 22/11/19 09:19:48
投稿者: rose11
|
---|---|
sk 様
|
![]() |
投稿日時: 22/11/20 15:58:56
投稿者: ニャッチュ
|
---|---|
提示されているVBAコードを見る限りでは
|
![]() |
投稿日時: 22/11/21 03:39:45
投稿者: MMYS
|
---|---|
rose11 さんの引用: rose11さんが、初心者と自覚されているうちは、あまり気にする必要はないと思いますが、私だったら、下記のように書きます。なお、動作検証していません。そのままでは動かいないと思います。なお、私は普段、SQLで操作しており、ADOオブジェクトの直接アクセスは不備があると思います。あくまでロジック・コーディング規約の視点です。 Option Explicit Const msEmployeeCode As String = "社員コード" Const tbTable1 As String = "T_test1" Const tbTable2 As String = "T_test2" Const tbTable3 As String = "T_test3" Const tbTable4 As String = "T_test4" Private Sub cmdRegist_Click() RegistNewRecord End Sub Private Sub RegistNewRecord() '新規レコード登録 Dim CN As New ADODB.Connection Dim strErrorMessage As String On Error GoTo ErrorTrap strErrorMessage = "" Set CN = CurrentProject.Connection CN.CursorLocation = adUseClient CN.BeginTrans strErrorMessage = AddRecordAtoB(tbTable1, tbTable2, CN) If strErrorMessage <> "" Then GoTo ErrorTrap strErrorMessage = AddRecordAtoB(tbTable3, tbTable4, CN) If strErrorMessage <> "" Then GoTo ErrorTrap CN.CommitTrans CN.Close Set CN = Nothing Exit Sub ErrorTrap: If strErrorMessage = "" Then MsgBox Err.Description, vbCritical Else MsgBox strErrorMessage, vbCritical End If CN.RollbackTrans CN.Close End Sub Private Function AddRecordAtoB(strTableA As String _ , strTableB As String, CN As ADODB.Connection) As String 'レコード追加 A⇒B '成功時は""を返す。エラー時はエラーメッセージを返す。 Dim rsA As New ADODB.Recordset Dim rsB As New ADODB.Recordset Dim strEmployeeCode As String On Error GoTo ErrorTrap Set rsA = New ADODB.Recordset Set rsB = New ADODB.Recordset rsA.Open strTableA, CN, adOpenKeyset, adLockOptimistic rsB.Open strTableB, CurrentProject.Connection, , adLockOptimistic Do Until rsA.EOF strEmployeeCode = rsA.Fields(msEmployeeCode).Value With rsB .AddNew .Fields(msEmployeeCode) = strEmployeeCode .Update End With rsA.MoveNext Loop rsA.Clone rsB.Clone Set rsA = Nothing Set rsB = Nothing AddRecordAtoB = "" Exit Function ErrorTrap: rsA.Close rsB.Close Set rsA = Nothing Set rsB = Nothing AddRecordAtoB = Err.Description End Function ・コードは第三者が読む事を前提に書きましょう。 ・コードは可読性を考えてて書きます。 ・コメントなしでも、作成者の意図が伝わるのがベスト。 ・コードはメンテナンスされるもの。簡単に修正できるようにします。例えば、テーブル名やフィールド名は変更される。と考なければなりません。 ・ハードコーディングはご法度 業務は常に変化します。仕様変更に備え、フィールド名などは定数にして、定数でアクセスします。 例) T_Table!社員コード = strEmpCode ↓ Const msEmployeeCode As String="社員コード" T_Table.Fields(msEmployeeCode).Value = strEmpCode ・プロシージャ名は、名前だけで、処理内容が推測できること。 ・プロシージャ名は動詞で始める ・変数名は、名前だけで、作成者の意図が理解できること。 ・名前は省略しない。英和辞書で意味が分かるようにする。 例) strEmpCode str と Code は作成者の意図が理解出来ます。しかし、Empは第三者に作成者の意図が理解出来ません。 またプロシージャ名は右上のコンボボックスでリストが出ます。このとき、アルファベット順に並びます。そしてコードは Ctrl+Space でインテリセンスが働きます。ですので、それを踏まえてプロシージャ名を決めます。 ・引数は重要度の高いものを先、重要度の低いものを後。 第三者がコードを読む時、コードの先頭から読みます。重要な引数が後方にあると、理解が遅れます。 例) Sub RegistTest(T_Table As ADODB.Recordset, strEmpCode As String) 呼び出し時、社員コードが常に変化するけど、レコードセットは変化しません。常に変化する社員コードを先に書いたほうが、第三者に作成者のコードの意図が伝わります。 ・プロシージャは単体テストできるようにする。 ・cmdRegist_Click()のコードできるだけ単純にする。(呼出元と実行部を分離) あと、更新系のコードはトランザクションが必須です。予測不能のエラーに備えましょう。特に業務でデータ破損は大問題です。 コーディング規約は、考え方が色々あります。 他にも注意点はありますが、重要なのは、作成者が仮に rose11さん 一人であっても、第三者に分かるように書くことです。なぜなら、業務内容の変化はよくあること。上司から修正依頼が来ます。でも、その時、当時なぜそのように書いたかコードの意図は忘れてますから。 |
![]() |
投稿日時: 22/11/21 10:10:07
投稿者: rose11
|
---|---|
sk 様
|
![]() |
投稿日時: 22/11/21 10:19:49
投稿者: rose11
|
---|---|
ニャッチュ 様
|
![]() |
投稿日時: 22/11/21 10:32:06
投稿者: rose11
|
---|---|
sk 様
|
![]() |
投稿日時: 22/11/21 11:24:21
投稿者: rose11
|
---|---|
MMYS 様
|