次の方法で共有

複数のサブフォームのRecordsetを低負荷で設定したい

Anonymous
2015-09-10T00:56:18+00:00

複数のサブフォームのRecordsetを低負荷で設定する方法を探しています。

■やりたい事。

1つメインフォームに複数のサブフォームがあります。

メインフォームはサブフォームを表示するためだけの器です。

例えば注文情報を蓄積した注文テーブルが1つあるとして、

サブフォーム毎に異なる条件でフィルタした注文レコードを表示させる、というようなものです。

下記の様なイメージのフォームを作成しています。

+メインフォーム

++サブフォーム1 (必要なレコード = Recordset_A * Filter_1)

++サブフォーム2 (必要なレコード = Recordset_A * Filter_2)

++サブフォーム3 (必要なレコード = Recordset_A * Filter_3)

++ (以下同様)

■課題、理由

しかし、単純に各サブフォームに

 ・レコードソース=Query_Recordset_A

 ・フィルタ=Filter_1

と設定すると、メインフォームの起動時に非常に重くなってしまいました。

サブフォームの数だけ新規にテーブルを読み込みに行ってると思いますので

当然かもしれません。

そこで、大元のRecordsetは共通していますので、1回読み込んだRecordsetを使い回す、

つまりVBAでフィルタ操作などして各サブフォームにセットしてやれば軽くなると考え、今回の方法を検討しています。

■試行

メインフォーム、各サブフォームのレコードソース、フィルターは空欄

下記コードをメインフォームのOpenイベントで実行。

(Open後にコマンドボタンのClickイベントでフィルタ条件を変更する事もある)

//コード

Dim rs As New ADODB.Recordset       '共通のRecordset

Dim rsC As New ADODB.Recordset      '作業用のRecordsetClone

' 共通Recordsetの取得

rs.CursorLocation = adUseClient

rs.Open "Query_Recordset_A", CurrentProject.Connection, adOpenForwardOnly, adLockReadOnly, adCmdTable

’ 必要なレコードを抽出

Set rsC = rs.Clone

rsC.Filter = "注文日=#" & Date & "#"

' サブフォームにRecordsetを設定

Set Me.subfサブフォーム1.Form.Recordset = rsC    ' ← ここでエラー

'Set Me.subfサブフォーム1.Form.Recordset = rs.Clone    ' ← これでもエラー

//結果

上記最後のRecordsetプロパティへrsCを設定しようとすると次のエラーが発生します。

「実行時エラー '-2147467259(80004005)':

'Recordset' メソッドは失敗しました: '_Form_サブフォーム1' オブジェクト」

なぜか「Recordset『メソッド』」になってますし、何が失敗したのか不明です。

また、別パターンとして、rs.Cloneを設定しようとすると、今度は別のエラーが発生します。

「実行時エラー '3001':

引数が間違った型、許容範囲外、または競合しています。」

ここで詰まってしまいました。

■質問

上記の回避策はありますでしょうか。

あるいは今回の目的では別の望ましい方法がありますでしょうか。

どうぞ宜しくお願いします。

Microsoft 365 と Office | アクセス | 家庭向け | Windows

ロックされた質問。 この質問は、Microsoft サポート コミュニティから移行されました。 役に立つかどうかに投票することはできますが、コメントの追加、質問への返信やフォローはできません。

0 件のコメント コメントはありません

質問作成者が受け入れた回答

Anonymous
2015-09-10T08:21:58+00:00

最初にボタンやタブによるフィルター切替も試してみたのですが、実際には利用上煩わしかったため、

ユーザーの積極的に利用する意欲を削ぎかねないと判断し、これらの手法は不採用になってしまいました。

3つのフォームは常時表示しているということですね。

レコードセットを使い回すということですが、

まず、抽出条件を設定しないレコードセットを読み込む。

Cloneを作成して、Filterを設定する。

ということのようですが、

ヘルプには、

Filterで抽出するより、レコードセットを開くときに、SQLのWHERE句で抽出条件を設定したほうが高速だという記載があります。

これを考えたら、Filterを使うことでそれほど高速化されるとは思えません。

すなおに、サブフォームのレコードソースに抽出条件付きのクエリを設定すればいいのかなと、思います。

ReadOnlyで開いているようなので、フォームの「レコードセット」プロパティを「スナップショット」に設定しておけば、負荷も軽減できます。

あと、フォームを開くのを高速化する目的でしたら、私なら下記のような設計を採用するかな。

サブフォーム1のみソースオブジェクトを設定しておいて、

「タイマー時」のイベントで、サブフォーム2、サブフォーム3 のソースオブジェクトを設定する。

これなら、サブフォーム1 のレコードを読み込み終了と同時にメインフォームが表示されて、

その後、サブフォーム2、サブフォーム3のレコードが読み込まれる。

形になります。

ユーザーは無反応のまま長時間待たされるということは回避できます。

なお、Me.subfサブフォーム1.Form.Recordset に Recordsetオブジェクト(ADO) を Set するという構文は

問題無いでしょうか。Me.subfサブフォーム1.Form.Recordset はメソッドと認識されるのでしょうか。

私自身は、ADOレコードセットをフォームに連結することにメリットがあるとは思っていないので、実運用で採用したことはなく、この件に関しては、アドバイスできるものは持っていません。

他の方の回答をお待ち下さい。

この回答は役に立ちましたか?

0 件のコメント コメントはありません

質問作成者が受け入れた回答

Anonymous
2015-09-10T08:18:58+00:00

> rs.Open "Query_Recordset_A", CurrentProject.Connection,

> adOpenForwardOnly, adLockReadOnly, adCmdTable

ADODB.Recordset オブジェクトを

フォームにバインドさせるのであれば

Connection プロパティではなく

AccessConnection プロパティが返す

ADODB.Connection オブジェクトを渡すようにされた方がよいでしょう。

(2015/09/10 18:47追記)

バインドされたフォームのレコードを編集したい場合は、

Access のバージョンによってはむしろ

Connection プロパティの方がよい場合もあります。

Connection プロパティで問題がなければ

上記のコメントは無視して下さい。

この回答は役に立ちましたか?

0 件のコメント コメントはありません

5 件の追加の回答

並べ替え方法: 最も役に立つ
  1. Anonymous
    2015-09-11T00:42:00+00:00

    返信ありがとうございます。

    AccessConnection プロパティ

    これは知りませんでした。ご指摘ありがとうございます。

    ただ、下記の様にしてオープンする事はできましたがフォームへのバインドで相変わらず強制終了されてしまいました。

    rs.Open "Query_Recordset_A", CurrentProject.AccessConnection, adOpenForwardOnly, adLockReadOnly, adCmdTable

    Set Me.subfサブフォーム1.Form.Recordset = rs.Clone  ' ← エラー

    なお、検索し直してみると、MSDNでもちゃんとサンプルがありました。

    ADO レコード セットをフォームに連結します。

    https://msdn.microsoft.com/ja-jp/library/office/Ff835419.aspx?f=255&MSPPError=-2147217396

    勉強します。

    この回答は役に立ちましたか?

    0 件のコメント コメントはありません
  2. Anonymous
    2015-09-10T07:40:02+00:00

    返信ありがとうございます。

    今回は一つのサブフォームで表示されるレコード数が多くない事もあり、

    一覧性を重視した作りを検討しています。

    なので多少重いのは仕方ないんですが、少なくともサーバー側とネットワーク側への負荷を減らせて、

    かつバックエンドファイルへのアクセスも減らして安定化に寄与できれば、と考えています。

    最初にボタンやタブによるフィルター切替も試してみたのですが、実際には利用上煩わしかったため、

    ユーザーの積極的に利用する意欲を削ぎかねないと判断し、これらの手法は不採用になってしまいました。

    なお、Me.subfサブフォーム1.Form.Recordset に Recordsetオブジェクト(ADO) を Set するという構文は

    問題無いでしょうか。Me.subfサブフォーム1.Form.Recordset はメソッドと認識されるのでしょうか。

    この回答は役に立ちましたか?

    0 件のコメント コメントはありません
  3. Anonymous
    2015-09-10T01:43:52+00:00

    現状で重くなっている原因は、下記の2点ですよね。

    複数のフォームを読み込んでいる。

    複数のレコードセットを読み込んでいる。

    レコードセットを使うとしても、

    複数のフォームを生成している。

    は解消されませんよね。

    また、複数のフォームがあるのですから、Cloneを使うなりして、複数のレコードセットを生成する必要があるので、

    複数のフォームを生成している。

    も解消されませんよね。

    > あるいは今回の目的では別の望ましい方法がありますでしょうか。

    こちらで検討すべきかと。

    下記の方法を提案します。

    タブコントロールにはサブフォームを配置しない。

    サブフォームをメインフォーム上に配置してから、サブフォームの上に移動させる。

    これで、サブフォームはタブコントロールの上に載っているように見えます。

    実際はタブコントロールの子コントロールではないですが。

    タブコントロールの「変更時」イベントでサブフォームにFilterを設定する。

    この方法だと、

    読み込むフォームは一つ。レコードセットも一つ。ということで開くとき重いというのは解消されます。

    デメリットとして、ページを切り替え時に再読み込みが発生するので重くなる可能性がありますが、

    通常は抽出対象フィールドにインデックスを設定しておけば、問題になるほど重くなることはないと思います。

    設定例

    サブフォームのデザインビューでフィルタープロパティに、規定の抽出条件を設定しておいて「読み込み時にフィルターを適用」を「はい」にしておきます。

    タブコントロールの変更時

    Private Sub タブ1_Change()

        With Me.subfサブフォーム1.Form

        Select Case Me.タブ1.Value

        Case 0

            .Filter = "抽出条件1"

        Case 1

            .Filter = "抽出条件2"

        Case 2

            .Filter = "抽出条件3"

        End Select

       .FilterOn = True

        End With

    End Sub

    この回答は役に立ちましたか?

    0 件のコメント コメントはありません