質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

Q&A

解決済

2回答

11028閲覧

ACCESS VBA Recordsetオブジェクトの受け渡し方について

DreamTheater

総合スコア1095

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

SQL Server

SQL Serverはマイクロソフトのリレーショナルデータベース管理システムです。データマイニングや多次元解析など、ビジネスインテリジェンスのための機能が備わっています。

Access

Accessはマイクロソフトによるリレーショナルデータベース管理システムです。オブジェクト指向のアプリケーション作成に対応しており、テーブルや編集をはじめ、クエリ生成、入力フォーム作成、レポート作成など一通りの機能を備えています。

0グッド

0クリップ

投稿2020/02/28 04:48

質問の経緯

5年ほど前、前任者からACCESS-VBAの業務システムを引き継ぎ現在に至ります。

当該業務システム利用中に突然エラーが発生することが稀に発生していました。
「オブジェクト変数またはWithブロック変数が設定されていません」というエラーだったと
記憶しております。

原因と思しき箇所を改修後、同エラーは発生しなくなりましたが、改修前のRecordsetオブジェクトの
受け渡し方が本当に誤りなのか自信がなく質問させて頂いた次第です。

エラーの傾向

  • 同日何度も実行している業務ロジックで突然エラーが発生する。
  • エラーが発生する業務ロジックは複数あるが、ロジックに特徴がある。(後述)
  • 業務システム(ACCESS)を再起動して全く同じ操作を実施すると問題なく終了する。

エラーが発生する業務ロジックの特徴

コードイメージは必要最低限、その他はコメントで表現します。

'---------------------------------------------------- 'SQLServerに接続しSELECT実行結果を戻り値で返す孫関数 '---------------------------------------------------- Private Function Select実行() As ADODB.Recordset Dim db As New ADODB.Connection db.Open "~SQLServer接続文字列~" Set Select実行 = db.Execute("~SQL(SELECT文)~") End Function '---------------------------------------------------- 'SELECT結果をフォームに表示する子サブルーチン '---------------------------------------------------- Private Sub Select結果画面表示(rs As ADODB.Recordset) Do Until rs.EOF '取得したレコードに対して各カラム値をフォームに出力する処理 rs.MoveNext Loop End Sub '---------------------------------------------------- 'フォームの検索ボタンクリック時、イベントプロシジャから '呼び出される親サブルーチン '---------------------------------------------------- Public Sub 検索処理() Call Select結果画面表示(Select実行) End Sub

疑問事項

  • SQLServerへの接続は孫関数で行っているが、コネクションを解放していない。

 ⇒ここで解放してしまうと、呼び元のSelect結果画面表示がレコードセットに
アクセスできないと理解。

  • 上位のサブルーチンではこのコネクションを解放する術がない。

自分は正しいコードと思えませんでした。

改修概要

  1. 親サブルーチン(検索処理)でSQLServer接続を行い、コネクションオブジェクトを孫関数に渡す。
  2. Select結果画面表示が終わったらコネクションを解放する。

以上の改修を行ってから、同事象は発生しなくなりました。
一応の自己解決。

確認して頂きたいこと

  • 改修前のコードは間違っているという判断で良いでしょうか?
  • 上記以外に改修案がありましたらご教示頂きたく。

補足情報(FW/ツールのバージョンなど)

OS:Windows7 / Windows10
ACCESS:Office2010 / Office365(1902)
DB:SQLServer2008R2

おわりに

記載していない業務ロジックに不具合がある可能性も重々承知しておりますが、改修前のようなRecordsetオブジェクトの渡し方についての是非についてコメントを賜りたく投稿しました。
よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

改修前のコードは間違っているという判断で良いでしょうか?

はい、間違っていると思います。

上記以外に改修案がありましたらご教示頂きたく。

質問の改修案でいいと思いますが、、、、やるとするなら、

クラスモジュールにして、
コンストラクタでSQLServer接続を行い、デストラクタでコネクションを解放するようにする。
Select結果画面表示はクラスのメソッドにする。
そうすれば、クラスの参照が終われば、自動でコネクションは解放されるので、解放し忘れがなくなる。

投稿2020/02/28 06:09

hatena19

総合スコア33699

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DreamTheater

2020/02/28 06:13

回答ありがとうございます。 モヤモヤがスッキリ晴れました。 クラスモジュール化する案なら解放漏れのリスクも解消出来ますね。 アドバイス感謝します!
guest

0

DBやRecordsetは作法として明示的にcloseした方が健康的ですけど、スコープ外になると勝手に開放してくれます。

Nothingはメモリの節約になるのか?

Recordsetをパラメータで渡すのは良いとしても、インスタンスがpublicで定義されているような場合もあるので、無駄とは思わず明示的にcloseする方が良いでしょうね。

投稿2020/02/28 06:15

sazi

総合スコア25173

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DreamTheater

2020/02/28 06:20

解説ありがとうございます。 スコープ外 = 孫関数から戻る だとすると、運良く動いていただけということになりますね。
sazi

2020/02/28 06:27

この場合、パラメータで受け取っている側が終了しても開放はされず、その変数を定義している所がスコープです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問