第11回 実践 クライアント/サーバーデータベースソリューション 第10回 第12回


Type 7 DB Serverを使ったクライアントアプリケーション

Access,VB5,Jetデータベースエンジンを利用した
C/Sシステム構築に関する考察,実験および実践

秋月巌ソリューション事務所
秋月 巌 AKIZUKI,Iwao


新しい技術とエンジニア

 最近,現場の開発者がどのような姿勢で最新の技術に接しているのかがわからなくなってきた.Microsoftが提供する最新技術は,その利点は認めるにしても現場での運用には難点があるものも多いから現場のエンジニアが注意深くなるのも当然だろう.
 また,新しい技術を使わなくても大抵の開発案件はこなせるという現実もある.テクノロジーのターゲットにインターネットが設定されることによって,多くの技術がレイドバックしたということも,最新技術に対する関心が弱くなったことの原因と思える.
 技術者にとって,新しい技術を習得することは,本来楽しいことのはずである.しかし,それが不安定さとの引き換えということになると,苦痛にかわってくる.しかもそれは周到な調査の結果の後にわかるのである.もし多くの工数を消費する調査を廃止したらどうなるのだろうか? つまり,Microsoftのキャッチフレーズを鵜呑みにして,設計開発にとりかかるのである.その結果ははっきりしている.調査の廃止によって節約できた工数の数倍の時間を,その後の仕様変更のために費やすことになるだろう.しかも工数の増加が全工程の後半部で判明するため,プロジェクトに与える影響ははかりしれない.

Visual Basicによる千年王国

 現在,日本のプログラム開発の現場において,もっとも使われている開発ツールは間違いなくVisual Basicである.そして,ユーザーが新しいツールに興味を示さなくなる傾向は,年々強くなってきている.そう,開発者はVisual Basicから,離れようとしないのである.そして,Visual Basicによって開発するにしても,最新のプログラミング方法を取り入れようとはしていない.この傾向は何かに似ている.
 業務プログラムの開発者といえば,COBOLプログラマであるという時代が久しく続いた.開発者は最新の技術を持つエンジニアであるというよりは,標準化が進んだ共通言語を理解する者であるというポジションを与えられた.おそらく,Visual Basicも同じような位置付けを与えられ,開発者の共通の教養となっていくのだろう.
 しかし,これではつまらない.皆が同じようなプログラムを同じように書くのでは活性化も行なわれないし,開発者のモチベーションを維持することはできない.

独創的な利用

 本連載がそうであるように,私自身はMicrosoftの技術を独創的に利用するように心がけている.最新の高水準テクノロジーよりは,やや低水準の技術を使い,独自の実装を心がけた方が全般としてはうまく動作するからである.
 ここで紹介しているDB Serverも,最新の高機能なコンポーネントを利用するというよりは,処理の各部をコーディングするというスタイルである.この連載を読む人は,解説を読みながら必要な部分を自分のプログラムに採用すればよい.
 また,今までは実験的要素,研究的な色づけも強かったが,今回は前号で解説したType7 DB Serverにアクセスするクライアントアプリケーションを紹介する.連載開始から1年近く経過して,初めて実用として使えるものを見せられるようになったのである.

「著者情報検索」アプリケーション

 サンプルアプリケーションはVisual BasicのサンプルデータベースであるBIBLIO.MDBを利用した「著者情報検索」アプリケーションである(図1).検索条件に著者を検索するための文字列を入力して[検索]ボタンをクリックすることで,必要なデータを取得することができる.検索の結果得られるのは著者の情報だけでなく,著作や出版社名なども取得できるリレーションナルデータベースプログラムである.動作はType7 DB Serverと協調して動作し,純粋なSocketアプリケーションなので,インターネット経由での動作も可能である.

図1:著者情報検索アプリケーション(メインフォーム)
図1:著者情報検索アプリケーション(メインフォーム)

 サーバーにType7 DB Serverを使用するため,技術的にはType7 DB Clientとの間に違いはない.ただ,マスター詳細フォームを採用しているため,ひとつのフォームで2つのレコードセットを扱っている.それに従い,レコードセットを区別するためのフラグ変数を用意することで,サーバーから送信されてきたデータが,どちらのレコードセットを扱うためのものなのかを判別している.

サンプルアプリケーションの構成

 図2は,著者情報検索アプリケーションをプロジェクトエクスプローラで表示した様子である.2つのプロジェクトに格納されている,2つのフォームとひとつのクラスモジュールによって構成されている.

図2:著者情報検索アプリケーションプロジェクト
図2:著者情報検索アプリケーションプロジェクト

 図1のメインフォームから呼び出される接続設定フォーム(図3)は,Type7 DB Serverへの接続方法を指定する.図3の設定(デフォルト値)では,クライアントとサーバーが同じマシンに指定されている.リモートで接続する場合は,ODBCの設定として必ずType7 DB Serverが起動しているマシンに登録されているDSNを使用する必要がある.

図3:接続設定フォーム
図2:著者情報検索アプリケーションプロジェクト

 MakeRecordsetClsクラスモジュールは,Type7 DB Clientで使用されたものと同等のものである.ただ,レコード数を取得するためのRecordCount関数が追加されている.このクラスモジュールはRecordsetオブジェクトを作成するためのクラスモジュールとして汎用的に設計されている.

動作の概要

 このプログラムは,検索条件を入力して[検索]ボタンをクリックしたユーザーのアクションによって,次のような処理を行なう.


複数のレコードセットを使用

 このように著者名を表示するためのrsAuthorレコードセットと,著書を表示するためのrsTitleレコードセットをWinsock2_DataArrivalイベントプロシージャで操作している.今までのDB Clientは常にひとつのレコードセットしか扱っていなかったので,受信したデータが,どのレコードセットのデータであるかで混乱することはなかった.
 それを整理するためにレコードセットの作成時にレコードセットラベルを設定している.レコードセットラベルといっても,単にステータスを判断するための変数である.
 次のコードは,それぞれcmdSend_ClickイベントプロシージャとgetTitleプロシージャに記述されている.
rsName = "Author"
Winsock2.SendData _
 "SELECT * FROM Authors WHERE Author like '" & _
 Trim(txt_param.Text) & "%'"

rsName = "Title Query"
Winsock2.SendData SQLstat
 それぞれ,SQL文を送信する直前に,rsName変数にレコードセットの名称を設定している.
 これらのラベルに対応して処理を分岐しているのが,Winsock2_DataArrivalイベントプロシージャの次の部分である.

Select Case rsName 
    Case "Title Query"
      | (rsTitleレコードセットを作成するための処理を記述)
    Case "Author"
      | (rsAuthorレコードセットを作成するための処理を記述)
 この仕組みさえ理解すれば,「著者情報検索」アプリケーションの動作を理解することは簡単である.

検索処理

 次のコードはテキストボックスに未入力の状態で,[検索]ボタンをクリックした場合のエラーハンドラである.エラーがあった場合には,入力を促すメッセージボックスが表示される.

If Len(Trim(txt_param)) = 0 Then
    MsgBox "検索文字列を指定してください"
    Exit Sub
End If
 テキストボックスが未入力の状態だと,SQL文のWHERE条件に長さ0の文字列が指定されるので,有効な検索を行なうことができない.実用的なアプリケーションを作成するためには,必要な処理である.
 次のコードでは,検索するためのSQL文をサーバーに送信する.

resultSet = ""
rsName = "Author"
Winsock2.SendData _
 "SELECT * FROM Authors WHERE Author like '" & _
 Trim(txt_param.Text) & "%'"
 送信前に結果の文字列を格納するためのバッファであるresultSet変数をクリアし,レコードセットラベルを設定する.
 この照会文はType7 DB Serverに送信され,検索処理が実行される.受け取った結果を処理するのは,DataArrivalイベントプロシージャ内である.DataArrivalイベントプロシージャに記述された以下の処理は,受け取った結果を,GetDataメソッドを使いresultSet変数に格納している.

Private Sub Winsock2_DataArrival _
 (ByVal bytesTotal As Long)
    Dim strData As String
    Winsock2.GetData strData, vbString
    resultSet = resultSet & strData
 resultSet変数の初期化をここで行なわないのは,結果セットの受信が1回で終わらない可能性があるからである.つまり,ひとつのレコードセットを作成するためのデータを受信するために, DataArrivalイベントプロシージャが複数回呼び出されることがある.これはType7 DB Serverが,特定数のレコードでデータを分割して返信するからである.この仕様はパフォーマンス上の理由による.巨大な文字列データをVisual Basicで扱うと,処理速度が極端に低下することを防いでいる.

検索結果の受信

 次の条件文は,レコードセットの全データを受信し終わったかどうかを判別している.
If InStr(resultSet, "Result Start") > 0 _
 And InStr(resultSet, "Result End") > 0 _
 Then
 レコードセットの始点と終点を指示する文字列Result StartとResult Endがデータに含まれていれば,レコードセットのデータをすべて取得しているということになる.これを確認してからRecordsetオブジェクトの生成にとりかかることで,未完成のレコードセットを作成してしまうことを防いでいる.この方法はもっとも安全性の高い方法である.しかし,全データを受信する前に受信済みのデータから順次Recordsetオブジェクトを作成してゆけば,パフォーマンスはさらに改善可能である.

Recoedsetオブジェクトの作成

 Recordsetオブジェクトの生成方法は,Type7 DB Clientと同様である.まず,Recordsetオブジェクトを作成するためのオブジェクトを宣言する必要がある.次の宣言は,Recoedsetオブジェクトを作成するためのオブジェクトとして,MakeRecordsetCls型を指定している.

Set rsAuthor = New MakeRecordsetCls
 MakeRecordsetCls型は,Visual Basicのクラスによって定義されており,その名称はクラスの名称である.RecordsetオブジェクトはMakeRecordsetユーザー定義メソッドの呼び出しによって行なわれる.

rsAuthor.MakeRecordset (resultSet)
 引数にレコードセットデータが格納された文字列型変数resultSetを渡すことで,クラスの内部にRecordsetオブジェクトを作成する.
 Recordsetオブジェクトは,最終的に次のように表現される.

rsAuthor.dsRecordset
 dsRecordsetプロパティは,MakeRecordsetCls内でADODB.Recordset型として定義されているdsRecordsetオブジェクトへの参照を保持している.

データ連結

 テキストボックスへのデータ連結を行なうためには,BindingCollectionオブジェクトを使用する.次の2行のコードでは,BindingCollectionオブジェクトを宣言し,そのDataSourceプロパティに前述の「rsAuthor」 MakeRecordsetClsオブジェクトを設定している.MakeRecordsetClsクラスがデータソースになれるのは, クラスのDataSourceBehaviorプロパティが「1 - vbDataSource」に設定されているからである(図4).

Set colBind = New BindingCollection
Set colBind.DataSource = rsAuthor
図4:MakeRecordsetClsクラスのDataSourceBehaviorプロパティを「1 - vbDataSource」に設定
図4:MakeRecordsetClsクラスのDataSourceBehaviorプロパティを「1 - vbDataSource」に設定

テキストボックスへのデータ連結

 テキストボックスへのデータ連結は,BindingCollectionオブジェクトのAddメソッドを使用して行なわれる.次のコードでは,3つのTextboxコントロールに対して,3つの項目を割り当てている.

colBind.Add txt1, "Text", _
 rsAuthor.dsRecordset.Fields(0).Name
colBind.Add txt2, "Text", _
 rsAuthor.dsRecordset.Fields(1).Name
colBind.Add txt3, "Text", _
 rsAuthor.dsRecordset.Fields(2).Name
 Addメソッドに指定された3つの引数は,連結するコントロールの名称,データ型,連結する項目の名前である.
 ところでBindingCollectionオブジェクトのDataSourceプロパティに設定されているのは,あくまでも「rsAuthor」MakeRecordsetClsオブジェクトであって,Recordsetオブジェクトではない.実は,データ連結が実施されるとMakeRecordsetClsオブジェクトの内部でGetDataMemberイベントが発生する.そのGetDataMemberイベントプロシージャで,連結するレコードセットとして「dsRecordset」Recordsetオブジェクトが指定されているのである.

参照するオブジェクト

 Recordsetオブジェクトを作成したり,データ連結を実現するためには,図5のように,Microsoft Data Source InterfacesとMicrosoft ActiveX Data Objects 2.0 Libraryを[プロジェクト]-[参照設定]で指定する必要がある.

図5:Microsoft Data Source InterfacesとMicrosoft ActiveX Data Objects 2.0 Libraryを参照設定で指定
図5:Microsoft Data Source InterfacesとMicrosoft ActiveX Data Objects 2.0 Libraryを参照設定で指定

マスター詳細フォームを使ったデータ表示

 ここまでで解説した処理で,「著者ID」「著者名」「誕生年」の表示が可能になった.「著者情報検索」アプリケーションは,フォームに表示されている著者の著作を表示する機能がある.1人の著者が発行する著作の数は不定数である.つまり,1対多の関係で表示されるマスター詳細フォームによって,表示される必要がある.
 マスター詳細フォームを使用したデータベースアプリケーションの作成には,いくつもの方法が考えられる.Microsoft Accessのようにマスター詳細フォームを自動的に設定するような機能を持つ開発ツールもあるが,Visual Basicはコードの記述によって,そのリンクを実装しなければならない.
「著者情報検索」アプリケーションのケースでは,著者情報の表示が変更されるたびに,その著者の著作データを取得する必要がある.
 では,著者情報の表示が変更されるのはどのような場合だろうか? ひとつは最初にデータが表示されるときであり,もうひとつはナビゲーションボタンがクリックされるときである.ならばそれらの処理が実行されるときに,著作データを取得するためのプロシージャを呼び出せばよい.

著作情報の取得

 そのプロシージャがgetTitleプロシージャである.このプロシージャ自体は,Type7 DB ServerにSQL文を送信する機能しかもっていない.
 次のプロシージャでは,最初に取得したデータを格納するためのバッファをクリアする.

resultSet = ""
 次のコードでは,検索のためのSELECT文を動的に生成している.

SQLstat = "SELECT Title, Titles.ISBN," & _
 "[Year Published], [Company Name] "
SQLstat = SQLstat & "From Publishers "
SQLstat = SQLstat & "Inner Join "
SQLstat = SQLstat & "([title author]" & _
 "INNER JOIN Titles ON [title author].ISBN " & _
 "= Titles.ISBN) "
SQLstat = SQLstat & "ON Publishers.PubID" & _
 "= Titles.PubID "
SQLstat = SQLstat & "Where Au_ID = "
SQLstat = SQLstat & Trim(txt1.Text)
 Where句以下で指定されているtxt1は著者IDを表示するためのTextboxコントロールである.
 次のコードでは,レコードセットの名前を設定し,Type7 DB ServerにSQL文を送信している.

rsName = "Title Query"
Winsock2.SendData SQLstat
複数のレコードセットを区別する

 レコードセットの名前を設定とはいっても,サーバーにレコードセットの名前を送信しているわけではない.この次にサーバーから返信されるレコードセットデータの内容がTitle Queryのものであるということを判別するためのクライアント側のフラグである.
 クライアント側のフラグによってレコードセットを判別する方法は,同時に2つ以上のクエリーを実行するような場合には使用することはできない.クエリーの処理時間は未定なので,どの順序でデータが返信されるか判別できないからである.よって,Type7 DB Serverのクライアントアプリケーションを作成する場合には,すべてのクエリー要求がシリアライズされなければならない.
 この制限をクリアするためには,サーバーがデータを送信するごとにヘッダ情報としてレコードセットの名称を付与するか,あるいは複数のコネクションを用いて別々にデータを返信することが必要になる.

著作情報の受信とDataGridコントロールへの連結

 次の条件分岐の一節は,レコードセットデータを受信するDataArrivalイベントプロシージャに記述されている.

Case "Title Query"
    Set rsTitle = New MakeRecordsetCls
    rsTitle.MakeRecordset (resultSet)
    Set DataGrid.DataSource = rsTitle
 受信したレコードセットデータがTitle Queryのものの場合のみ処理されるコードである.Recordsetオブジェクトを生成するための処理は著者名を表示する場合と同様である.著作情報はDataGridコントロールにデータ連結されるため,Textboxコントロールに連結する場合よりも,ずっと簡単である.DataGridコントロールのDataSourceプロパティにMakeRecordsetCls型のオブジェクトを指定すればよい.BindingCollectionオブジェクトを宣言する必要もない.

「著者情報検索」アプリケーションの実行

 完成したアプリケーションを実行すると,著作情報の表示は速いのだが,著者名を検索表示するのに,3秒ほどかかる.実用の範囲外ではないが,データ量の割には時間がかかり過ぎる.調べてみると,AuthorsテーブルのAuthor項目にインデックスが設定されていないからだということがわかった.インデックスを設定すれば,「著者情報検索」アプリケーションは快適に動作する(図6).
 ところで,BIBLIO.MDBはJet3.0データベースエンジンの形式で提供されている.このデータベースエンジンは,Microsoft AccessでいうとAccess 95に相当する.そのためMicrosoft Access 97でインデックスを設定する前にデータベースの変換作業を行なう必要がある.変換時には別名の新しいMDBファイルを作成するので,リネームして置き換えるか,再度ODBCのDSNの設定を行なう必要がある.

図6:Author項目にインデックスを設定することで高速化が実現
図6:Author項目にインデックスを設定することで高速化が実現

次号ではさらに進歩

 Type7 DB Server & Clientには多くの課題が残されているが,次号ではどの部分を改善するべきだろうか? 私は現在,3つの案を検討している.
 ひとつは,簡単なプログラミングでデータの更新が可能になるような仕組みの実装である.現在のType7 DB Server & Clientでは,データの更新をするためには,Insert文やUpdate文をクライアント側のプログラミングで生成しなければならない.データベースアプリケーション開発者が各々これを実装することは今日的ではない.当然コンポーネントとして提供されるべきである.
 もうひとつは,クライアントアクセスのメカニズムのコンポーネント化である.今回クライアントアプリケーションを作成して気づいたのだが,WinsockコントロールのDataArrivalイベントプロシージャにデータアクセスのためのコードを記述しなければならないのは,洗練されているとは言い難い.やはりWinsockコントロールは,別のコントロールにラップされて開発者に提供されるべきだろう.
 最後のひとつは,マルチスレッド化である.Type7 DB Serverは各接続ごとに別々のプロセスを起動する.それゆえ1接続ごとに5MBのメモリを消費する.単にこの問題に対応するためであれば,DBsvrプロジェクトのclsDBaccessクラスのInstancingプロパティの値をMulyiUseに設定すればよい.これでType7 DB Serverはマルチスレッドで動作し,接続ごとのメモリ消費も極端に低減される.しかしype7 DB Serverの問題点のひとつであるサーバー側のポートを接続ごとにオープンするという特徴はかわらない.この仕様はインターネットでの使用には適さない.
 この問題は,マルチユーザーマネージメントサーバーとDBアクセスサーバー(図7)を同じプロセスで実行することで解決可能である.しかし,そのように仕様を変更すると,今度はマルチプロセスで動作させることはできない.私はこの問題について,今までJetデータベースエンジンの新型が出てから対応することを表明してきた.それは,当時のJetデータベースエンジン3.0(現行は3.5)のODBCドライバを,マルチスレッドで動作させるとパフォーマンス上の問題があったからである.また,次期バージョンはMicrosoft SQL Serverとエンジン互換の製品になるという噂も流れていた.そして,このエンジンがVisual Basic 6.0にも搭載されると思っていたことも理由のひとつである.
 しかし,現行のJetデータベースエンジンであるVer 3.5のODBCドライバでは,パフォーマンス劣化の問題は発生しない.また次期バージョンのエンジンは,Microsoft Access 2000に搭載されるはずだが,このリリースタイミングはまだ発表されていない.
 これらのことを考慮すると,もうマルチスレッド専用モデルに移行してもよいように思えるのである.実はクライアント側のデータアクセスモジュールをコンポーネント化するにあたって,マルチスレッド専用モデルとシングル/マルチ兼用モデルとでは,アーキテクチャが大きく違ってしまう.そのため,兼用モデルでクライアント側のコンポーネント化をすすめると,後で専用モデルに移行したときに大きな変更が発生してしまう.
 何が,最優先課題かは,あと,1ヶ月間,悩むことにしよう.

図7:マルチユーザーマネージメントサーバーとDBアクセスサーバー(現在は別プロセスで動作)
図7:マルチユーザーマネージメントサーバーとDBアクセスサーバー(現在は別プロセスで動作)

リスト1:メインフォームに記述された全ソースコード
Option Explicit
Private unloadFlg As Integer
Private rsAuthor As MakeRecordsetCls
Private rsTitle As MakeRecordsetCls
Private colBind As BindingCollection
Private rsName As String
Dim resultSet As String

Private Sub getTitle()
    Dim SQLstat As String
    resultSet = ""
    SQLstat = "SELECT Title, Titles.ISBN, [Year Published], [Company Name] "
    SQLstat = SQLstat & "From Publishers "
    SQLstat = SQLstat & "Inner Join "
    SQLstat = SQLstat & "([title author] INNER JOIN Titles ON [title author].ISBN = Titles.ISBN) "
    SQLstat = SQLstat & "ON Publishers.PubID = Titles.PubID "
    SQLstat = SQLstat & "Where Au_ID = "
    SQLstat = SQLstat & Trim(txt1.Text)
    rsName = "Title Query"
    Winsock2.SendData SQLstat
End Sub

Private Sub cmdConn_Click()
    Winsock2.Listen
    ' DBsvrRBへ接続
    ' DBsvrからの接続要求待ちにする
    cmdConn.Enabled = False
    If Winsock1.State <> sckClosed Then Winsock1.Close
    Winsock1.RemoteHost = frm_option.txt_host.Text
    Winsock1.Connect
End Sub

Private Sub cmdFirst_Click()
    rsAuthor.dsRecordset.MoveFirst
    cmdFirst.Enabled = False
    cmdBack.Enabled = False
    cmdNext.Enabled = True
    cmdLast.Enabled = True
    Call getTitle
End Sub

Private Sub cmdBack_Click()
    rsAuthor.dsRecordset.MovePrevious
    cmdNext.Enabled = True
    cmdLast.Enabled = True
    If rsAuthor.dsRecordset.BOF Then
        rsAuthor.dsRecordset.MoveNext
        cmdFirst.Enabled = False
        cmdBack.Enabled = False
    Else
        Call getTitle
    End If
End Sub

Private Sub cmdLast_Click()
    rsAuthor.dsRecordset.Movelast
    cmdFirst.Enabled = True
    cmdBack.Enabled = True
    cmdNext.Enabled = False
    cmdLast.Enabled = False
    Call getTitle
End Sub

Private Sub cmdNext_Click()
    rsAuthor.dsRecordset.MoveNext
    cmdFirst.Enabled = True
    cmdBack.Enabled = True
    If rsAuthor.dsRecordset.EOF Then
        rsAuthor.dsRecordset.MovePrevious
        cmdNext.Enabled = False
        cmdLast.Enabled = False
    Else
        Call getTitle
    End If
End Sub

Private Sub cmdSend_Click()
    ' DBsvrへSQL文を送信
    If Len(Trim(txt_param)) = 0 Then
      MsgBox "検索文字列を指定してください"
      Exit Sub
    End If
    resultSet = ""
    rsName = "Author"
    Winsock2.SendData "SELECT * FROM Authors WHERE Author like '" & Trim(txt_param.Text) & "%'"
End Sub

Private Sub Command1_Click()
    frm_option.Show
End Sub

Private Sub Form_Unload(Cancel As Integer)
    If Winsock2.State <> sckClosed Then Winsock2.Close
End Sub

Private Sub Winsock1_Connect()
    ' ローカルホスト名とODBCデータソース名をDBsvrRBへ送信
    Winsock1.SendData frm_option.txt_localHost.Text & "," & frm_option.txt_dsn.Text
End Sub

Private Sub Winsock1_SendComplete()
    ' 接続要求が終了
    Winsock1.Close
End Sub

Private Sub Winsock2_ConnectionRequest(ByVal requestID As Long)
    ' クライアントDBsvr(ActiveX EXE)からの接続要求時に発生
    ' 接続処理の完了
    If Winsock2.State <> sckClosed Then Winsock2.Close
    Winsock2.Accept requestID
    ' 検索ボタンを使用可にする
    cmdSend.Enabled = True
End Sub

Private Sub Winsock2_DataArrival(ByVal bytesTotal As Long)
    Dim strData As String
    ' クライアントDBsvr(ActiveX EXE)からデータを受け取る
    Winsock2.GetData strData, vbString
    resultSet = resultSet & strData
    '-------------------------------------
    If InStr(resultSet, "Result Start") > 0 And InStr(resultSet, "Result End") > 0 Then
        Select Case rsName ' 実行されたレコードセットによって作成するレコードセットを変更
            Case "Title Query"
                Set rsTitle = New MakeRecordsetCls
                ' テキスト(resultSet)を元にレコードセットを作成
                rsTitle.MakeRecordset (resultSet)
                ' クラスを使ってDataGridに連結
                Set DataGrid.DataSource = rsTitle
            Case "Author"
                Set rsAuthor = New MakeRecordsetCls
                ' テキスト(resultSet)を元にレコードセットを作成
                rsAuthor.MakeRecordset (resultSet)

                ' BindingCollectionオブジェクトを定義し,データソースにクラスを指定
                Set colBind = New BindingCollection
                Set colBind.DataSource = rsAuthor

                ' BindingCollectionオブジェクトを使ってテキストボックスにデータ連結
                colBind.Add txt1, "Text", rsAuthor.dsRecordset.Fields(0).Name
                colBind.Add txt2, "Text", rsAuthor.dsRecordset.Fields(1).Name
                colBind.Add txt3, "Text", rsAuthor.dsRecordset.Fields(2).Name

                MsgBox rsAuthor.RecordCount & "レコードのデータが見つかりました"

                ' ナビゲーションボタンの使用可
                If rsAuthor.RecordCount > 1 Then
                    cmdNext.Enabled = True
                    cmdLast.Enabled = True
                Else
                    cmdFirst.Enabled = False
                    cmdBack.Enabled = False
                    cmdNext.Enabled = False
                    cmdLast.Enabled = False
                End If
                Call getTitle
        End Select
    End If
End Sub



VB Magazine ライブラリ | Visual Basic WorkGroup
int21 ホームページ | PCDN ホームページ


Copyright (c) 1998 int21 Corporation All Rights Reserved.
For questions or comments, please send mail to: pcdn@int21.co.jp