tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルDAOによるOpenDatabaseについて
記事No15195
投稿日: 2011/06/01(Wed) 10:48
投稿者しまちゃん
OS:WindowsXP SP3
VB6.0でAccess2003のデータをDAOで開いてデータを表示するプログラムです。

Dim db As DAO.Database
Dim rsID As DAO.Recordset
Dim rsTM As DAO.Recordset
'----- フォームのLoad -----
Private Sub Form_Load()
    Set db = DBEngine.Workspaces(0).OpenDatabase("D:\Data\ID.mdb")
    Set rsID = db.OpenRecordset("ID", dbOpenDynaset)
'    db.Close: Set db = Nothing

    Set db = DBEngine.Workspaces(0).OpenDatabase("D:\Data\master.mdb")
    Set rsTM = db.OpenRecordset("TM", dbOpenDynaset)

    txtID = rsID![No]
    DataDisp
End Sub

Private Sub cmdNext_Click()
    rsTM.MoveNext
    DataDisp
End Sub

Private Sub DataDisp()
    txtName = rsTM![名前]
End Sub

最初、Database型のオブジェクト db へ、ID.mdb をセットし ID をテーブルを開いて No を表示しています。
次に、同じ db へ別の、master.mdb をセットし TM をテーブルを開いて 名前 を表示しています。
同じ db で、別のデータベースを開いてもどちらのテーブルも参照できるのはなぜでしょうか?
コメント行にしてますが、db.Close: Set db = Nothing を有効にした後、master.mdb をセットし TM をテーブルを開くと ID テーブルは参照できなくなります。

[ツリー表示へ]
タイトルRe: DAOによるOpenDatabaseについて
記事No15198
投稿日: 2011/06/01(Wed) 12:45
投稿者魔界の仮面弁士
変数とインスタンスを切り離して考えてみてください。

たとえば先のコードは、

 Set db1 = DBEngine.Workspaces(0).OpenDatabase("D:\Data\ID.mdb")
 Set rsID = db1.OpenRecordset("ID", dbOpenDynaset)
 'db1.Close
 'Set db1 = Nothing
 Set db2 = DBEngine.Workspaces(0).OpenDatabase("D:\Data\master.mdb")
 Set rsTM = db2.OpenRecordset("TM", dbOpenDynaset)
 Set db = db2

というコードと同じ意味です。

[ツリー表示へ]
タイトルRe^2: DAOによるOpenDatabaseについて
記事No15201
投稿日: 2011/06/01(Wed) 14:44
投稿者しまちゃん
> たとえば先のコードは、
>
>  Set db1 = DBEngine.Workspaces(0).OpenDatabase("D:\Data\ID.mdb")
>  Set rsID = db1.OpenRecordset("ID", dbOpenDynaset)
>  'db1.Close
>  'Set db1 = Nothing
>  Set db2 = DBEngine.Workspaces(0).OpenDatabase("D:\Data\master.mdb")
>  Set rsTM = db2.OpenRecordset("TM", dbOpenDynaset)

>  Set db = db2 ----- は何をしているのですか?

また、

    Set db = DBEngine.Workspaces(0).OpenDatabase("D:\Data\ID.mdb")
    Set rsID = db.OpenRecordset("ID", dbOpenDynaset)

    Set db = DBEngine.Workspaces(0).OpenDatabase("D:\Data\master.mdb") ----- (a)
    Set rsTM = db.OpenRecordset("TM", dbOpenDynaset)

この場合、rsID が (a) の後でも ID.mdb を参照できるのはなぜなのでしょうか?
(a) で、db は master.mdb を参照するように変更になったのではないのでしょうか

インスタンスがいまいちわかりません。

[ツリー表示へ]
タイトルRe^3: DAOによるOpenDatabaseについて
記事No15202
投稿日: 2011/06/01(Wed) 16:55
投稿者魔界の仮面弁士
>  Set db = db2 ----- は何をしているのですか?
No15195 のコードで、変数 db は Form1 のモジュールレベル変数になっていましたよね。
単に、そのモジュールレベル変数への代入操作です。

一方、db1, db2 は Sub Form_Load() 内のプロシージャレベル変数を想定しています。
こちらの変数は、プロシージャが End Sub に到達した時点で解放されます。


> この場合、rsID が (a) の後でも ID.mdb を参照できるのはなぜなのでしょうか?
ID.mdb が閉じられていないからです。


> (a) で、db は master.mdb を参照するように変更になったのではないのでしょうか
その通りです。ですから今後、db.OpenRecordset の呼び出しは、
ID.mdb ではなく master.mdb に対して行われるようになります。

ただし、ID.mdb が閉じられたわけではありません。単に、変数 db が
その Database を参照しなくなったというだけのことです。

ID.mdb が閉じられたわけではありませんから、rsID はそのまま利用できますし、
ID.mdb を開いている Database オブジェクトのインスタンスを再入手すれば、
変数 db を使わずとも、引き続き ID.mdb の操作が可能です。



なお、 Database オブジェクトは Databases コレクションとして保持されています。

Debug.Print DBEngine.Workspaces(0).Databases.Count
Debug.Print DBEngine.Workspaces(0).Databases(0).Name
Debug.Print DBEngine.Workspaces(0).Databases(1).Name
Debug.Print DBEngine.Workspaces(0).Databases(0).Recordsets.Count
Debug.Print DBEngine.Workspaces(0).Databases(1).Recordsets(0).Name

[ツリー表示へ]
タイトルRe^4: DAOによるOpenDatabaseについて
記事No15203
投稿日: 2011/06/01(Wed) 18:14
投稿者しまちゃん
> > この場合、rsID が (a) の後でも ID.mdb を参照できるのはなぜなのでしょうか?
> ID.mdb が閉じられていないからです。

ID.mdb を閉じるには rsID.Close: Set rsID = Nothing でいいのでしょうか

> なお、 Database オブジェクトは Databases コレクションとして保持されています。
>
> Debug.Print DBEngine.Workspaces(0).Databases.Count
> Debug.Print DBEngine.Workspaces(0).Databases(0).Name
> Debug.Print DBEngine.Workspaces(0).Databases(1).Name
> Debug.Print DBEngine.Workspaces(0).Databases(0).Recordsets.Count
> Debug.Print DBEngine.Workspaces(0).Databases(1).Recordsets(0).Name

Databases コレクションをみて、ID.mdb が閉じていないことがわかりました。
set した順番に Close しないかぎり残っているのですね。
変数と同じイメージで代入したデータベースが換わったのにおかしいなと勘違いしていました。
どうもありがとうございました。 ついでで悪いのですが、初心者でもインスタンスについてわかりやすいページがありましたら教えてください。

[ツリー表示へ]
タイトルRe^5: DAOによるOpenDatabaseについて
記事No15204
投稿日: 2011/06/01(Wed) 20:54
投稿者魔界の仮面弁士
> ID.mdb を閉じるには rsID.Close: Set rsID = Nothing でいいのでしょうか
それは、レコードセットを閉じるコードです。
データベースを閉じるには、Database オブジェクトの Close メソッドを呼び出します。


データベースは 2 つ同時に開いているのですから、それを操作するには
Database 型の変数も 2 つ用意しておいた方が良いでしょう。そうすれば、
 db1.Close
 db2.Close
のようにして、それぞれを任意のタイミングで閉じることができます。

一応、変数に保持しておかなくとも、Databases コレクションから
再取得することはできますが…自分で管理しておいた方が便利かと。


ちなみに、こうしたコレクションに自動追加されるという動作は、Form も同じだったりします。
Forms コレクションというやつですね。
    Debug.Print Forms.Count     'ロードされているフォームの数
    Debug.Print DoEvents        '表示されているフォーム数

蛇足ですが:
 Set F = New Form2    'フォームを作成しただけでは、Forms.Count や DoEvents の値は変化しない
 Load F               'ロードされる事により、Forms.Count が +1 される。
 F.Show               'それが表示されると、DoEvents の値についても +1 される。
 F.Hide               '非表示状態になると、DoEvents の結果が -1 される。
 Unload F             'アンロードされると、Forms.Count も -1 される。
 Set F = Nothing



> set した順番に Close しないかぎり残っているのですね。
Set順と Close 順はこの場合、直接は関係ないかと。

重要なのは「使わなくなったら閉じる」という事です。
それが Database であれ Form であれ ファイルであれ。



> 変数と同じイメージで
db や rsID も変数ですよね。


> 代入したデータベースが換わったのにおかしいなと勘違いしていました。
これは管理上の問題に過ぎません。データベース以外でもあっても同じことが言えます。

たとえばファイル操作で、

Dim f As Integer
f = FreeFile()
Open "C:\a.txt" For Output As #f
'Close #f

f = FreeFile()
Open "C:\b.txt" For Output As #f

のようにした場合、a.txt と b.txt が同時に開かれることになります。

FreeFile からは、それぞれ 1 と 2 が返されるのですが、
変数 f を使いまわしたため、変数 f は 2 を指している状態です。

しかし、a.txt は閉じられていませんので、エクスプローラー等から
a.txt を削除することはできません。また、変数 f を使わずに
「Print #1, "テスト"」などのようにして書き込む事さえできます。

[ツリー表示へ]
タイトルRe^6: DAOによるOpenDatabaseについて
記事No15209
投稿日: 2011/06/02(Thu) 12:28
投稿者しまちゃん
> データベースは 2 つ同時に開いているのですから、それを操作するには
> Database 型の変数も 2 つ用意しておいた方が良いでしょう。

> 重要なのは「使わなくなったら閉じる」という事です。


そのようにします。


> たとえばファイル操作で、...........

この例よくわかりました。 ありがとうございました。
午前中いろいろためし少しわかってきた気がします。 わかてくると、とんちんかんな質問もしてしまたようですね.....すみませんでした。

[ツリー表示へ]
タイトルインスタンスについて
記事No15205
投稿日: 2011/06/01(Wed) 21:24
投稿者魔界の仮面弁士

> ついでで悪いのですが、
折角なので、インスタンスについて、もう少し掘り下げてみましょう。


DAO で mdb を扱う際には、Database オブジェクトを
 Dim db As DAO.Database
 Set db = 〜〜
のように、変数に Set して使うことが多いですよね。この場合、
「Database クラスのインスタンスを変数 db にセットしている」あるいは、
「Database 型のオブジェクトを変数 db にセットしている」と表現できます。

インスタンスとはクラスを実体化させたものであり、
VB6 では「オブジェクト」という表現が使われる事が多いです。

大雑把にいってしまうと、Database、Form、TextBox、App 等は、
それぞれが『クラス』であり、そのクラスが実体化されたものが
『インスタンス』であるという事です。


----------------------
これだけだと分かりにくいと思うので、もう少し別の例を出してみます。


たとえば、ツールバーにある TextBox コントロールをフォームに貼ると、
画面上に Text1 や Text2 ができますよね。Text1 と Text2 はどちらも TextBox です。

これらはそれぞれ同じ型のオブジェクトなわけですが、別の物です。
それぞれは独立しており、Text1.Text を書き換えても Text2.Text には影響しません。

――ここまでは良いですよね?


この場合、ツールバーにある物は TextBox のクラスであり、
そしてフォーム上に実体化(インスタンス化)された物については
TextBox オブジェクトと呼ぶことができます。分かりにくい表現かも知れませんが。


さて、これを変数を介して利用してみた場合、
  Private txt As TextBox
  Private Sub Form_Load()
   Set txt = Me.Text1
  End Sub
のような使い方も可能です。

この場合、変数 txt も Text1 も、同じテキストボックスを参照することになります。
実体は一つなので、どちらを使ってアクセスした場合も同じ結果が得られます。

 'Text1.Text = "A"
 txt.Text = "B"
 MsgBox Text1.Text    ' ← B と表示される


そしてこの後、変数 txt を
 Set txt = Me.Text2
にすると、txt に対する操作は Text2 に対する操作として扱われます。

ですが、Text1 の実体は無くなったわけではありません。
フォーム上に残っている以上、変数 txt に参照されなくなった後も、
Text1 のコントロールは引き続き利用できます。


今回問題となったコードも同じこと。

変数 db が master.mdb を指すようになったとしても、
ID.mdb を開いている Database インスタンスは残っていますから、
rsID は引き続き利用できるわけです。

変数 txt が Text2 を指すようになったとしても、
Text1 コントロールはフォーム上に残っているので、
テキストボックスを使い続けることができるのと同じように。



> 初心者でもインスタンスについてわかりやすいページがありましたら

わかりやすいかどうかは別として……"インスタンス" について
書かれた資料としては、ヘルプで言うとこのあたりが該当します。


[Visual Basic の使用方法]
├[プログラミング ガイド]
│└[Visual Basic の基本]
│ └[プログラミングの基礎]
│  └[オブジェクトの使用方法]
│   ├[オブジェクトとは]★
│   └[オブジェクトの作成]☆
└[コンポーネント ツール ガイド]
 └[ActiveX コントロールの作成方法]
  └[ActiveX コントロール作成に関する用語]
   └[コントロール作成に関する用語]★

上記から少し抜粋してみると、以下のような記述が見つかります。

堅苦しい文章なので読みにくいかも知れませんが、書いてある内容は
今回解説した内容と同等なので、該当ページについて目を通しておいてください。


| オブジェクトとは、1 つの単位として扱うことのできるコードとデータの組み合わせです。
| コントロールやフォームなどアプリケーションの一部も 1 つのオブジェクトであり、
| アプリケーション全体も 1 つのオブジェクトです。

| ツールボックス上のコントロールはクラスを表します。コントロールのオブジェクトは、
| フォーム上に配置するまでは存在しません。コントロールをフォーム上に配置すると、
| コントロールのクラスのコピーである "インスタンス" が作成されます。
| クラスの各インスタンスが、アプリケーションで参照する各オブジェクトになります。

| Visual Basic を使って開発するコントロールは、実際にはコントロール クラスです。
| コントロールは、コントロール クラスから作成されます。コントロールを
| フォームに配置すると、そのコントロール クラスの インスタンス が作成されます。

[ツリー表示へ]
タイトルRe: インスタンスについて
記事No15211
投稿日: 2011/06/02(Thu) 18:20
投稿者しまちゃん
> 変数 txt が Text2 を指すようになったとしても、
> Text1 コントロールはフォーム上に残っているので、
> テキストボックスを使い続けることができるのと同じように。

わかりやすい例をありがとうございました。
午後いろいろためしてみました。
今はまだ頭の中がごちゃごちゃしています。 明日も一度整理してみます。

> わかりやすいかどうかは別として……"インスタンス" について
> 書かれた資料としては、ヘルプで言うとこのあたりが該当します。

ヘルプをゆっくり呼んでみます。

[ツリー表示へ]