Visual Basic 6.0がやってくる!
Visual Basic 6.0データアクセス新機能(後編)
福岡 寿和 FUKUOKA,Toshikazu
富士通SSL
OLE DBは,“汎用”データアクセスパラダイムを導入する低水準の新しいインターフェイスです.すなわち,OLE DBはISAM,Jet,リレーショナルデータソースに限定されず,形式や記憶方法にも関係なく任意のデータ型を処理することができます.実際,この汎用性は,Excelの表計算ソフト,テキストファイル,Microsoft Exchange などのグループウェア,または,ActiveXサーバーなどのビジネスオブジェクトに存在するデータにもアクセスできると言うことを意味しています.
Visual Basic Version 6.0では,OLE DBとのプログラミング インターフェイスの ADO を介してOLE DBのフレキシビリティを利用することができます.また,独自のOLE DBプロバイダを作成することもできます.
ODBCにも言えることですが,OLE DBも複雑なインターフェイスのためにVisual Basicから直接アクセスするようには設計されていません.そのため,ODBCにDAOやRDOがあるようにOLE DBには,ActiveXデータオブジェクト(ADO)があります(図1).そして,ODBCがAPIによりDAOやRDOと接続しているのに対して,OLE DBとADOは,COMにより接続しています.OLE DBは,データを公開するデータプロバイダとデータを使用するデータコンシューマ,データを処理するサービスコンポーネントから構成(図2)されていて,その間もCOMベースで接続されています.
図1:Visual Basic 6.0での各データアクセス手法の構造

図2:OLE DBのデータコンシューマとサービスコンポーネントの関係

ADOのオブジェクト構造は,「これで,ユニバーサルデータアクセスが実現できるのか?」と心配になるくらい単純なものです(図3).
図3:ADOのオブジェクト構造図

しかし,ADOの難しさは,このオブジェクト構造図には表われてきません.なぜなら,Connectionオブジェクト,Commandオブジェクト,Recordsetオブジェクトには,個々のOLE DBプロバイダ固有の動的プロパティが含まれています.この動的プロパティが,ADOの柔軟性と共に難しさの原因となります.プログラムを作成するときには,基本的なプロパティのみ使って汎用性を高めるのか,動的プロパティを使って最適化していくのかを考慮する必要があります.
●
Connectionオブジェクト
ADOを使うときには,まずConnectionオブジェクトを作成して,OLE DBプロバイダとの接続を確立します.Connectionオブジェクトを作成するには,次のようなコードを実行します.
Set adcnnTest = New ADODB.Connection
次にConnectionStringプロパティに接続文字列を設定します.たとえば,ODBCを使うときは(データソース名をVBMとする),
adcnnTest.ConnectionString ="Provider=MSDASQL;DSN=VBM"
を実行します.なお,Visual Basic 6.0に付属しているOLE DBプロバイダごとの設定値を表1にまとめてみました.
表1:OLE DBプロバイダ別ConnectStringプロパティ設定値
| OLE DBプロバイダ |
ConnectStringプロパティの例 |
| Microsoft OLE DB Provider for ODBC Drivers |
Provider=MSDASQL;User ID=<ユーザーID>Data Source=<データソース名> |
| Microsoft Jet 3.51 OLE DB Provider |
Provider=Microsoft.Jet.OLEDB.3.51;Data Source=<MDBファイル名> |
| Microsoft OLE DB Provider for SQL Server |
Provider=SQLOLEDB;User ID=<ユーザーID>;Data Source=<サーバー名> |
| Microsoft OLE DB Provider for SQL Server |
Provider=SQLOLEDB;User ID=<ユーザーID>;Data Source=<サーバー名> |
| Microsoft OLE DB Provider for Oracle |
Provider=MSDAORA; User ID=<ユーザーID>;Data Source=<データベース別名> |
最後に,Openメソッドを使って,OLE DBプロバイダと実際に接続します.
AdcnnTest.Open
●
Errorオブジェクト
ADOでは,メソッドの実行などで複数のエラーが発生するときがあります.それは,指定したOLE DBプロバイダが検出したエラーです.このとき,ADOはそのすべてのエラーをErrorsコレクションの中に保存します(リスト1・図4).もちろん,別の ADO 操作でエラーが発生すると,以前のErrors コレクションは消去され,最新のErrorsコレクションが作成されます.
図4:ADOのエラーメッセージ

また,ADOは,エラーが通知されるとOn Error Gotoでトラップできるエラーイベントも発生させるので,Errorオブジェクトに対する処理をモジュール内で一個所に集めることができます.
エラーが発生しない ADO 操作は Error オブジェクトに影響を与えないので,Errors コレクションを消去する場合は,Clear メソッドを使用します.
リスト1:Errorsコレクションの使用例
strMsg = ""
With conADOConn
For iintLoop = 1 To .Errors.Count
strMsg = strMsg & .Errors(iintLoop - 1).Description & _
"(" & .Errors(iintLoop - 1).NativeError & ")" & vbCrLf & _
.Errors(iintLoop - 1).Source & _
"(" & .Errors(iintLoop - 1).SQLState & ")" & _
vbCrLf & vbCrLf
Next
End With
MsgBox strMsg, vbOKOnly + vbExclamation, App.Title
|
●
Recordsetオブジェクト
Recordsetオブジェクトを作成して,OpenメソッドによりSQL文,テーブル名,Commandオブジェクトを指定し,これをConnectionオブジェクトと結合することで,検索結果をレコードセットとして生成します.Recordsetオブジェクトを作成するには,次のようなコードを実行します.
Set adrstTest = New ADODB.Recordset
次に引数に値を設定してOpenメソッドを実行するか,引数に対応したプロパティに値を設定してから,Openメソッドを実行します.今回は,説明の都合上,プロパティに値を設定してからOpenメソッドを実行することにします.
◆CusrorTypeプロパティ(省略可能)
OLE DBプロバイダが使うカーソルの動作モードを設定します(表2).この中で一番高速なのが,前方スクロールタイプカーソル,汎用性が高い(あらゆるモードで使える)のは,静的カーソル,Openメソッドなどの再発行をせずに他のユーザーの変更値を取得したいときは動的カーソルを使うことになります.
表2:CursorTypeの設定値
| CursorType |
説明 |
| AdOpenForwardOnly |
(デフォルト値)前方スクロールタイプカーソル.レコードを前方向のみにスクロールできることを除き,静的カーソルと同じ属性を持ちます.レコードセットを一度だけ読み込みならば,このカーソルにより性能が向上します |
| AdOpenKeyset |
キーセットカーソル.動的カーソルと同じような属性を持ちますが,他のユーザーが追加したレコードを表示せず,使用中のレコードセットから他のユーザーが削除したレコードへのアクセスを許可しません.他のユーザーが変更したデータは,表示することができます.つまり,レコード件数を変えないこと点が動的カーソルと異なっています |
| AdOpenDynamic |
動的カーソル.他のユーザーによる追加,変更および削除を見ることができます |
| AdOpenStatic |
静的カーソル.データの検索またはレポートの作成に使用するための,レコードの静的コピーです.他のユーザーによる追加,変更または削除は表示されません |
◆LockTypeプロパティ(省略可能)
OLE DBプロバイダが使うロック (同時実行制御) の種類を指定します(表3).
表3:LockTypeプロパティの設定値
| LockType |
説明 |
| adLockReadOnly |
(デフォルト値)読み取り専用.データの変更はできません |
| adLockPessimistic |
排他的ロック.通常,編集の際にプロバイダがデータソースでレコードをロックすることにより,確実にレコードを編集できます |
| adLockOptimistic |
共有的ロック.Updateメソッドを呼び出した場合のみ,プロバイダが共有的ロックを使用してレコードをロックします |
| adLockBatchOptimistic |
共有的バッチ更新.バッチ更新モードの場合に必要です. |
◆CommandTypeプロパティ(省略可能)
OpenメソッドのSource 引数が Command オブジェクト以外のときに,引数をOLE DBプロバイダが評価する方法を指定します(表4).
表4:CommandTypeプロパティの設定値
| CommandType |
説明 |
| AdCmdText |
コマンド文字列として評価する. |
| AdCmdTable |
指定値をテーブル名と評価して,テーブルからすべての行を返す SQL クエリーを生成する |
| AdCmdTableDirect |
テーブルからすべての行を返す |
| AdCmdStoredProc |
ストアド プロシージャとして評価する |
| AdCmdUnknown |
コマンド タイプが不明であることを指定します |
| AdCmdFile |
指定値をファイル名として,そこに保存(永続化)されたRecordset を復元する |
| AdExecuteNoRecords |
行を返さないコマンドまたはストアド プロシージャであることを示します |
各プロパティを設定したら,Openメソッドを実行します.
strSQL = "SELECT * FROM Titles"
adrstTest.Open strSQL,adcnnTest
このように作成されたレコードセットは,DAOやRDOのように,MoveFirst,MoveLast,MoveNext,MovePreviousなどのカレント行移動メソッドやBof,Eofプロパティなどを使うことができます.
●
Fieldオブジェクト
レコードセットのカレント行(現在行)の値を取得するためのオブジェクトがFieldオブジェクトになります.実際には,Fieldsコレクションの配列の添字を指定したり,連想配列としてFieldsコレクションを使って,フィールド名を指定して値を取得することが多いようです.
adrstTest.Fields(0).Value
adrstTest.Fields("Year Published").Value
●
Commandオブジェクト
Commandオブジェクトは,OLE DBプロバイダに問い合わせて,Recordsetオブジェクトを返します.パラメタクエリーやストアドプロシージャの実行も可能です.
Set adcmdTest = New ADODB.Command
Set adcmdTest.ActiveConnection = adcnnTest
adcmdTest.CommandText = strSQL
adcmdTest.Execute
adrstTest.Open adcmdTest
Commandオブジェクトの実行結果がレコードセットを返すときは,このオブジェクトを指定して,RecordsetオブジェクトのOpenメソッドを実行します.
●
Parameterオブジェクト
Parameterオブジェクトは,Commandオブジェクトのパラメタを指定します.入力パラメータ,出力パラメータのどちらでも指定できます.
Set adprmTest = New ADODB.Parameter
adprmTest.Type = adInteger
adprmTest.Size = 3
adprmTest.Direction = adParamInput
adprmTest.Value = intRoyalty
adcmdTest.Parameters.Append adprmTest
Typeプロパティによりパラメータの型を指定,Sizeプロパティでパラメータの長さを指定,Directionプロパティで入出力方向を指定,そして,Valueプロパティでパラメータの値を設定(もしくは取得)します.
ADO2.0のカーソルには,ローカルカーソルライブラリとデータプロバイダカーソルがあります.カーソルの選択は,ConnectionオブジェクトのOpenメソッド実行前にCursorLocationプロパティに値を設定することで行ないます.
- adUseClient:ローカルカーソル
- adUseServer:データプロバイダカーソル
- adUseClientBatch:バッチカーソル
ただし,バッチカーソルは,互換性のためにあるだけで,ADOでは,データプロバイダカーソルを宣言して,LockTypeプロパティでバッチ更新を指定します(リスト2).
どちらのカーソルを選択するかについてですが,汎用性ならばローカルカーソル,性能ならばデータプロバイダカーソルを選択することがひとつの目安です.
リスト2:バッチ更新
Dim adrstTitles As ADODB.Recordset
Dim strCnn As String
strCnn = "Provider=sqloledb;" & _
"Data Source=srv;Initial Catalog=pubs;User Id=sa;Password=;"
Set adrstTitles = New ADODB.Recordset
adrstTitles.LockType = adUseServer
adrstTitles.CursorType = adOpenKeyset
adrstTitles.LockType = adLockBatchOptimistic
adrstTitles.Open "titles", strCnn, , , adCmdTable
adrstTitles.MoveFirst
Do Until adrstTitles.EOF
adrstTitles.Fields("Type").Value = "self_help"
adrstTitles.MoveNext
Loop
adrstTitles.UpdateBatch
|
ADO2.0でもRDO1.0のように非同期実行ができます.対象は,Connection,RecordsetおよびCommandオブジェクトです.
●
Connectionオブジェクト
OpenメソッドのOptions引数にadAsyncExecuteを設定することで接続の非同期実行ができます.
adcnnTest.Open , , ,adAsyncExecute
Do While adrstTest.State = adStateConnecting
DoEvents
Loop
●
Recordsetオブジェクト
OpenメソッドのOptions引数にadAsyncExecuteを設定することで,レコードセット作成の非同期実行ができます.
adrstTest.Open strSQL,adcnnTest, , ,adAsyncExecute
Do While adrstTest.State = adStateFetching
DoEvents
Loop
●
Commandオブジェクト
ExecuteメソッドのOptions引数にadAsyncExecuteを設定することでコマンドの非同期実行ができます.
adcmdTest.Execute, , ,adAsyncExecute
Do While adcmdTest.State = adStateExecuting
DoEvents
Loop
ADO2.0では,ConnectionオブジェクトとRecordsetオブジェクトに対して,イベントドリブンによる非同期モードを用意しています(表5).イベントドリブンを有効にするためには,
Private WithEvents adcnnEvt As ADODB.Connection
のように変数の宣言時に「WithEvents」を付加します.この変数宣言は,Declarations部にしか記述できません.それは,このイベントドリブン変数宣言が行なわれるとオブジェクトボックスにその変数名が追加されて,すぐに対応したイベントのプロシージャ部を記述できるようになるからです(図5).
図5:「With Event」で宣言した変数はオブジェクトボックスで参照可能になる

表5:追加されるイベント
| オブジェクト |
イベント |
概要 |
| Connection |
BeginTransComplete |
トランザクションの開始直前に発生 |
| CommitTransComplete |
トランザクションの終了直後に発生 |
| RollBackTransComplete |
ロールバック直後に発生 |
| WillConnect |
接続する直前に発生 |
| ConnectComplete |
接続成功(もしくは失敗)直後に発生 |
| Disconnect |
切断完了直後に発生 |
| WillExecute |
コマンド開始直前に発生 |
| ExecuteCompleate |
コマンド終了直後に発生 |
| InfoMessage |
プロバイダから追加情報があるときに発生 |
| Recordset |
FetchProcess |
レコード取得時に定期的に発生し,取得済みレコード数と取得予定レコード数が返却される.これにより取得率を求めたりプログレスバーに進行状況を表示可能 |
| FetchComplete |
レコード取得が完了したときに発生 |
| WillChangeField |
フィールド値の変更直前に発生 |
| FieldChangeComplete |
フィールド値の変更直後に発生 |
| WillMove |
カレント行の移動直前に発生 |
| MoveComplete |
カレント行の移動直後に発生 |
| EndOfRecordset |
レコードセット最後に達した直後に発生 |
| WillChangeRecord |
カレント行のデータが変化する直前に発生 |
| RecordChangeComplete |
カレント行のデータが変化した直後に発生 |
| WillChangeRecordset |
現在のレコードセットのデータが変化する直前に発生 |
| RecordSetChangeCompleate |
現在のレコードセットのデータが変化した直後に発生 |
11月号に掲載した前編の図18で,ビジュアルデータマネージャに使われているミドルウェアがDAO/Jetのみであるように図示していますが,Visual Basic 6.0からは,DAOの他にADOをミドルウェアとして採用しています(図6).どのミドルウェアを使うかは,ビジュアルデータマネージャのツールバーで指定できます.
図6:Visual Basic 6.0のビジュアルデータマネージャが利用するミドルウェア

従来のDACを使うときは,このアイコンを選択して,該当するテーブルを開きます.DAC(データソース)とTextBoxコントロール(データコンシューマ)の連結も設計時に行なわれているため,とくに目新しい機能は使われていません.
DACもADODCも使わずにDAO/Jetのレコードセットを直接使っています.フォームの中で
Public mrsFormRecordset As Recordset
と宣言したファイルがそのレコードセットになります.実際にレコードの内容をTextBoxコントロールに設定するのは,modVisDataモジュールのDisplayCurrentRecordサブルーチンの中になります.
ADODCを使っています.ただし,ADOでオープンしたレコードセットを代入しています.ModVisDataモジュールのOpenTableプロシージャなどの中身を見るとその代入処理の場所ば見つかるでしょう(実際は,frmDataGridフォームのパブリック変数であるmrsFormRecordset変数を介してADOレコードセットとADODCを関連づけています).このモードで使われるOLE DBプロバイダは,AccessのときはOLE DB Provider for Microsoft Jet,その他を選択したときはMicrosoft OLE DB Provider for ODBCが選択されます.
このビジュアルデータマネージャを題材にして,ADOの実用的プログラムを解説してゆきたいと考えていましたが,実際にプログラムを動作させてみると,ADODCを選択したときに,1レコード目の第一フィールドの値がクリアされてしまうことが判明しました.Bibilo.mdbのTitleテーブルをADODCで開こうとすると図7のように表示され,実際に空白がフィールドに設定されてしまいます.ADODCで開く前に他の方法で開いたときには図8のように正常に表示されるので,ADODCかDataGridコントロールもしくはこの2つを組み合わせたときのみ発生する障害のいずれかであると推測されます.そこで,路線を変更して,この障害がどこに起因するか,またどうすれば回避できるのかを探ってみたいと思います.
図7:Bibilo.mdbのTitleテーブルをADODCで開く

図8:同じMDBファイルをADODC以外の方法で開いたところ


ビジュアルデータマネージャ
Titlesを正しく表示させるには
|
●
ADOを調査する
まずは,ADOについて調査してみます.ビジュアルデータマネージャでは,ADOでOpenしたレコードセットをADODCのレコードセットに受け渡しています.ADOレベルで値が取れてきているかを判定するために,ADOがレコードセットを作成した直後に先頭レコードのフィールド値をデバッグ表示してみたいと思います.ADOがレコードセットを作成しているのは,modVisDataのOpenTableプロシージャです.
Set rsADOTmp = New ADODB.Recordset
With rsADOTmp
.Open rsTmp.Name, _
conADOConn, adOpenStatic, _
adLockOptimistic, adCmdTable
End With
Set frmTmp.mrsFormRecordset = rsADOTmp
この直後に
Debug.Print rsADOTmp.Fields(0).Value
と記述して実行すると正しく値が取得できます.つまり,ADOからADODCにレコードセットを受け渡すところよりあと(受け渡しそのもの,ADODC内部,ADODCとDataGridコントロールの連結のどれか)に原因がありそうです.
●
ADODCを調査する
ADOではきちんと値が取れてきていますので,次はADOのレコードセットをADODCに設定する部分を疑ってみましょう.場所は,frmDataGridのForm_Loadプロシージャです.
Set datDataCtl.Recordset = mrsFormRecordset
ここでも先ほどを同じように値が取れているかをデバッグ表示してみると
Debug.Print datDataCtl.Recordset.Fields(0).Value
値が取れてきているのが分かります.
●
DataGridコントロールを調査する
こうなってくるとADODCとDataGridの相性問題なのかもしれませんが,試しにレコードセットの設定や上記修正部分をコメントアウトして,設計時にプロパティを指定して実行すると一部表示が変ですが,値が表示されます(図9).
図9:設計時にプロパティを指定して実行すると値が表示される

ADODCとDataGridコントロールは,設計時にDataGridコントロールのDataSourceプロパティに値を設定しておくことで連結しています.これは,データコントロール(DAO)やRDC(RDO)時代からの連結方法です.普通は「昔からある方法なんだから,ここが変だとは考えられない」と思うかもしれません.しかし,使う側だけではなく,作成側やテスト側もそう思ってモノができ上がっている可能性だってあります.そこで,ADODCから新しく加わった実行時連結機能に切り替えてみます.まず,frmDataGridフォームのgrdDataGridコントロールのプロパティウィンドウで,DatSourceプロパティの値を空白クリアします.そして,同じフォームのForm_LoadプロシージャのADOのレコードセットをADODCに設定している行の次に,
Set grdDataGrid.DataSource = datDataCtl
と記述して実行すると,図9と同一の表示が表われます.どうやら,ADODCとDataGridコントロールは実行時連結することでデータを壊さずに表示できるようです.
●
完全な表示を求めて
しかし,まだ完全に正しい表示は得られていません.
引き続きいろいろ調査をしていると,偶然にもDataGridコントロールが最初にフォーカスを持っていないときは正しく表示されることがわかりました.これはDataGridコントロールが,セルがアクティブになったときセルに完全に表示されている単語までをハイライト表示するためのようです.そのため,DataGridコントロールを使う限りは回避できないものですが,先頭のセルをアクティブにしなくてもよいならば対応策はあります.
この対応策をどうやって発見したかと言いますと,実行時連結のタイミングを見たいために,Form_Loadではなく,新たにコマンドボタンコントロールを貼り付けて,その中で実行時連結を行なったら正しく表示されたのです.さらに,この貼り付けたコントロールのTabIndexプロパティを「0」に設定すると,設計時連結したDataGridコントロールでも正しく表示されます(図10).しかし,画面に無造作にコマンドボタンコントロールが表示されているのも無粋ですし,表示後にDataGridコントロールにフォーカスが移っていないのも使いづらいでしょう.
図10:DataGridコントロールからフォーカスが外れている場合には正しく表示される

そこで,
- コマンドボタンコントロールをDataGridコントロールの後ろに配置します(図11).このとき,コントロールのロックがかかっていると配置メニューが有効になっていないので,そのようなときはコントロールのロックを外してください.
図11:コマンドボタンコントロールをDataGridコントロールの後ろに配置する

- タイマーコントロールを貼り付けて,次のようなプロパティ値を設定します.
(オブジェクト名) tmrLoad
Enabled False
Interva 1
- Form_Loadプロシージャの最後で
tmrLoad_Enabled = True
とします.
- tmrLoad_Timerプロシージャの中で
tmrLoad.Enabled = False
grdDataGrid.SetFocus
と記述します.
しかし,この方法でも図9と同じ状態になってしまいます.解決方法は,DataGridコントロールにSetFocusせず,コマンドボタンコントロールのEnabledプロパティをFalseにすることで結果的にフォーカスがDataGridコントロールに移るように制御することです.tmrLoad_Timerプロシージャの中を
tmrLoad.Enabled = False
cmdDummy.Enabled = False
' grdDataGrid.SetFocus
と変更すると図11のように正しい表示になります.
ビジュアルデータマネージャ
Title Authorsを正しく表示させるには
|
Titlesテーブルは無事に表示することができました.しかし,ビジュアルデータマネージャには,Title Authorsテーブルのように間に空白が入っているテーブルだとADOで開けないという症状もあります(図12).
図12:データ内に空白が入っているテーブルだとADOで開けない

これは,ADOでレコードセットを作成しているところが原因です.Jetでは,空白を含む要素を使うときに[]で囲むことから類推して,modVisDataモジュールのOpenTableプロシージャの「.Open rsTmp.Name, conADOConn, ……」を「.Open "[" & rsTmp.Name & "]", conADOConn,……」と変更すると,TitleAuthorsテーブルも含めてすべてのテーブルが正しく表示できます.
ADO2.0では,RDS(Remote Data Service)と言ってADO Recordsetオブジェクトを,同一マシン内の異なるプロセスやネットワークを介した異なるプロセス間でリモート処理することができます.この機能を使うとまるで(OracleのPL/SQL表のように)ストアドプロシージャの戻り値に複数レコードが格納されているような処理を行なうことができます.
リモート処理できるのは,Recordsetオブジェクト以下の部分なので,呼び出し側用にADORライブラリ(Microsoft ActiveX Data Object Recordset 2.0 Library)が用意されています.このライブラリは,ADOライブラリと比べてCommand,ConnectionおよびParametersオブジェクトが含まれていない軽量なADOライブラリですから,呼び出し側が参照設定するのに最適なライブラリです.
●
RDS.DataSpace
RDS.DataSpaceは,RDSクライアントからRDSサーバーを呼び出す方法を提供しています.RDSサーバーは中間層(図13)にあるActiveX DLLやActiveX EXEのことで,RDSクライアントとの間は,http,https(HTTP Secure Socket),DCOM,COMプロトコルで接続されます.ここで注目したいのは,COM/DCOMだけではなくhttpやhttpsのプロトコルにも対応しているので,NTネットワークを構築しなくても利用も可能な点です.
図13:

●
RDSServer.DataFactory
RDSServer.DataFactoryは,RDSが標準で用意したRDSサーバープログラムです.このオブジェクトとRDSクライアントが接続することにより,指定されたデータソースの読み書きが可能です.通常はこのオブジェクトを使うことで事足りますが,httpやhttpsプロトコルを使うときは,ADISAPコンポーネントによりインスタンス化されるので,WebサーバーにInternet Information Serverを使ったイントラネット,インターネット,エクストラネットである必要があります.
●
RDS.DataControl
RDS.DataControlは,ADODCのRDS版でRDS.DataSpaceおよびRDS.DataFactoryを自動的に呼び出します.
クラスモジュールをデータソースとして指定できるようにするには,
- クラスモジュールのDataSourceBehavior プロパティにvbDataSourceを設定
- BindingCollectionオブジェクトのData Sourceプロパティにクラスモジュールを指定
- BindingCollectionオブジェクトにAddメソッドを使って,クラスモジュールをデータソースとして使いたいデータコンシューマを追加
という手順をとります.
実際には,この他にデータコンシューマが新しいデータソースを要求するときにGetDataMemberイベントが発生するので,データソースとなるクラスモジュールのClass_GetDataMemberプロシージャに初期化ロジックをコーディングします.また,メソッドとしてデータソースの操作メソッドを公開したりします.
●
OLE DBプロバイダ
Visual Basicを使用すると,「ActiveX DLLプロジェクトでDataSourceBehaviorプロパティをvbOLEDBProviderに設定することによって独自のOLE DBプロバイダを作成することができます」とありますが,クラスモジュールのInstancingプロパティにPrivate以外を設定してパブリッククラスとしても,DataSourceBehaviorプロパティにvbOLEDBProviderを設定することはできませんでした.
●
OLE-DB Simple Providerの利用
OLE DBプロバイダを0から作成できるかは不明ですが,OLE-DB Simple Providerをインプリメントしてクラスモジュールを作成することで,半オーダーメードのOLE DBプロバイダを作成することはできます.OLE DBプロバイダとして実装しなくてはいけないメソッドが始めから定義されるので,こちらの方法の方が手軽です.
- 参照設定で
Microsoft Data Source Interfaces
Microsoft OLE DB Simple 1.5 Provider Library
OLE DB Errors Type Library
の3つを指定します
- クラスモジュールのDeclarationsに
Implements OLEDBSimpleProvider
を記述して,OLE DB Simple Providerをインプリメントすることで,クラスモジュール内にOLEDBSimpleProviderオブジェクトが追加され,インプリメントされたイベントがプロシージャとして追加されます(表6)
表6:OLE DB Simple Providerのインターフェイス
| インターフェイス |
記述する処理 |
| addOLEDBSimpleProviderListener |
[データ変更通知イベント]複数のselect文を一度に処理するなどの複数行セットを扱うときは,その個数分だけリスナーを追加する.通常は,リスナーがないようならば追加するだけ(扱う行セットはひとつ)でよい |
| deleteRows |
管理しているデータから情報を削除する.また,リスナーのaboutToDeleteRowメソッドdeletedRowメソッドでリスナーにも通知する |
| find |
検索処理,カレント行の移動,カレント位置を返却する |
| getColumnCount |
カラム数を返却する |
| getEstimatedRows |
概算の行数を返却する(非同期実行の途中経過として使われる) |
| getLocale |
RFC 1766に基づいたLCIDを返却する |
| getRowCount |
行数を返却する |
| getRWStatus |
指定行,列の読み書き可能/不可能を返却する |
| getVariant |
指定行,列の値を返却する |
| insertRows |
管理しているデータに情報を追加する.また,リスナーのaboutToInsertRowメソッドとinsertedRowメソッドでリスナーにも通知する |
| inAsync |
非同期実行をサポートするかを返却する |
| removeOLEDBSimpleProviderListener |
複数行セットを扱っているときの後処理としてリスナーを削除する |
| setVariant |
指定行,列の値を更新する.また,リスナーのaboutToChangeCellメソッドとcellChagedメソッドでリスナーにも通知する |
| stopTransfer |
[実行完了イベント]非同期実行モードによる実行が完了したので,通常はとくに処理を記述する必要はない |
- 追加されたプロシージャに処理を記述します
BindingCollectionオブジェクトを使ってクラスモジュールをデータソースとして定義したときと異なり,このようにOLE DBプロバイダとしてクラスモジュールを定義することで,データアクセス機能をカプセル化することができます.
データアクセス系ウィザード
データオブジェクトウィザード
|
データオブジェクトウィザードは,Data Environmentオブジェクトをデータソースとするクラスモジュールを自動生成します.データオブジェクトウィザードは,さらにその作成したデータソースクラスモジュール(ウィザードで作成しなくてもよい)を指定してユーザーコントロールを自動生成します.
この2段階のウィザード操作により,データコントロールを使わないデータアクセスアプリケーション作成の最初の1歩の手間が軽減できます.生成されたモジュールを見るとヘッダコメントもきちんとつけられていて,比較的読みやすいコードになっていました.
データアクセス系ウィザード
データフォームウィザード
|
オブジェクトを作らずにデータアクセスアプリケーションを作りたいときは,データフォームウィザードを使います.データフォームウィザードの起動は,アドインからではなく,フォームモジュールの追加から選択します(図14).
図14:「フォームモジュールの追加」からデータフォームウィザードを起動する

生成できるフォームの種類は,
- 単一レコード
- グリッド(データシート)
- マスター/詳細
- 階層フレキシブルグリッド
- チャート
の4種類です.そして,データソースとしては,ADODC,ADO,クラスの3つから選択できます.
ADOをいろいろ触ってみて感じたのは,「遅い」ということです.また,プロパティがOLE DBプロバイダごとに追加可能という点も驚きでした.要は,DAOやRDOのように情報のアクセス手段をODBCという共通アクセスインターフェイスに閉じ込めるのではなく,それぞれに適したアクセス手段をOLE DBプロバイダで提供して,それをADOの動的プロパティとしてプログラムから使えるということです.Visual Basicのデータアクセスの歴史を見ると,「DAO/JetによるSQL文も含めた統一化」→「RDOによる呼び出しインターフェイスのみの統一化(SQL文はRDBMSごとに異なる)」→「ADOによる拡張性のある呼び出しインターフェイスの提供」のように変化してきています.
たとえば,RDBMSアプリケーションを作り始めて,取りあえず動き始めるまでならば,RDBMSに左右されないADOが比較的優位です.ただ,ADOがDAOやRDOと異なるのは,パフォーマンスチューニングやRDBMSに特化した使い方をしたくなったとき,手間はかかりますが,どうにかなるようなプロパティが提供される余地が残っているところです.これはADOの優位な点です.ただし,この手間は,RDBMSネイティブなVisual Basic用インターフェイス(SQL ServerならばRDO,Oracleならば,Oracle Objects for OLE)と変わらないし,パフォーマンス的には,まだまだネイティブなインターフェイスの方が優れているようです.
VB Magazine ライブラリ|
Visual Basic WorkGroup
int21 ホームページ|
PCDN ホームページ
Copyright (c) 1998
int21 CorporationAll Rights Reserved.
For questions or comments, please send mail to:
pcdn@int21.co.jp