ラベル エラー処理 の投稿を表示しています。 すべての投稿を表示
ラベル エラー処理 の投稿を表示しています。 すべての投稿を表示

2009年4月22日水曜日

Access の VBA でエラー処理

例えば、フォームにレコード を削除するためのボタンがあり、クリックされたときの処理を次のように記述したとする。

Private Sub btnDelete_Click()
    DoCmd.RunCommand acCmdDeleteRecord
End Sub

エラー処理を記述してないので、削除ボタンを押したときに「いいえ」を選択すると、

090422-003

実行時エラーのエラーのダイアログが表示される。

090422-002

 

エラー処理

エラーをキャッチして、エラー番号とエラー内容を表示するように変更するなら、

Private Sub btnDelete_Click()
On Error GoTo Err_Handler
    DoCmd.RunCommand acCmdDeleteRecord
    Exit Sub
    
Err_Handler:
    MsgBox Err.Number & " : " & Err.Description
End Sub

正常に処理されたとき、エラー処理に突入しないように Exit Sub の記述を忘れずに。

先ほどと同じ操作をすると、同じ内容がメッセージボックスに表示される。

090422-004

 

エラー処理の分岐

ところで、ユーザに上記のメッセージを見せる必要はないので、エラーの内容によってエラー処理を変えたい。この場合、先ほどのエラー番号で処理を分ける。

Private Sub btnDelete_Click()
On Error GoTo Err_Hander
    DoCmd.RunCommand acCmdDeleteRecord
    Exit Sub
    
Err_Handler:
    If Err.Number = 2501 Then
        Exit Sub
    Else
        MsgBox Err.Number & "/" & Err.Description
    End If
End Sub

Java ばかりいじっていたとき、エラー番号でトラップするのを見たときびびったけど ^^;

ちなみに Chapter 09 例外処理 - @IT によると、

VB.NETでは、On Error Gotoは「非構造化例外処理」という名前で呼ばれる。

 

後処理がある場合

もし、次のような要件がある場合は、

  • エラーの内容に応じて処理をしたい
  • 正常、エラーを問わず後処理が必要
Private Sub btnDelete_Click()
On Error GoTo Err_Handler
    DoCmd.RunCommand acCmdDeleteRecord

Finally:
    ' 後処理
    Exit Sub

Err_Handler:
    If Err.Number = 2501 Then
        ' このエラー独自の処理
    Else
        MsgBox Err.Number & "/" & Err.Description
    End If
    Resume Finally
End Sub

(cf. Access の VBA でトランザクション処理 – CSV ファイルからデータの登録)

処理がシンプルなときは Resume Next でもいいけれど、バグを誘発しそうなので Resume ラベル名 を使うことにしようかな。

2009年4月16日木曜日

Access の VBA でトランザクション処理 – CSV ファイルからデータの登録

トランザクションと言えば、やはりこの本。

未だ買ってすらいない。 パタッ(o_ _)o~†

昔からデータベースのこの辺がチンプンカンプン。入門レベルを読んでもトランザクション、排他制御になるとついていけない。いつかはちゃんと頭の中を整理したいのだけれど… (+_+)

 

クライアントから見たトランザクション

トランザクションの大枠については以下の図を参照。

異常なければコミット、異常があればロールバック。これだけ聞くとシンプルなのだけれど…。とりあえず、クライアントアプリがトランザクションを利用するときのテンプレートを書いておくことに。参考にしたのは以下の二つの記事。

Access の ADO については、「ActiveX Data Object : ADO入門講座」を。

 

テンプレート

以下、ADO でテーブルにレコードを追加するときのテンプレート。Java のように try ~ catch がないのでエラーハンドラと Resume を利用。

ポイントは、トランザクションが開始された後に異常が置きたらロールバック。正常異常を問わず、最後にデータベースへのコネクションを閉じる。ただし、その際コネクションが存在していることを確認すること。

Sub tmplADOTran()
On Error GoTo Err_Handler
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim blnTran As Boolean
    
    blnTran = False
    
    Set cn = CurrentProject.Connection
    Set rs = New ADODB.Recordset
    
    ' トランザクションの開始
    cn.BeginTrans                   '
    blnTran = True

    rs.Open "テーブル名", cn, adOpenKeyset, adLockOptimistic
    
    ' データを列ごとに追加する
    rs.addnew
    rs!列名 = "値"
    rs.Update
    
    ' コミット
    cn.CommitTrans
    blnTran = False
    
Finally:
    If Not rs Is Nothing Then rs.Close
    If Not rs Is Nothing Then cn.Close
    
    Exit Sub
    
Err_Handler:
    ' ロールバック
    If blnTran Then cn.RollbackTrans
    MsgBox "エラーが発生しました: " & Err.Description, vbOKOnly
    
    Resume Finally
End Sub

あぁ~、何かややこしいなぁ。 (+_+)

 

例. CSV ファイルのデータを登録

上記のテンプレートを元に、CSV ファイル (test.csv) のデータをテーブルに登録するコードを書いてみる。ただし、対象のテーブルは一つ。追加する先のテーブルの列は文字列型とする。

まず、データを追加するテーブルの名称と列の名前を保持する Table クラスを作成。(挿入 > クラスモジュール) 値を保持するだけなのでインスタンス変数は Public に。

Public name As String               ' テーブルの名称
Public cols As New Collection       ' 列の名前のコレクション

上記のテーブル情報を持ったオブジェクトと、データ元となるファイルへのパスを渡すとレコードを追加する関数は以下のようになる。

Sub insert(objTbl As table, strFilePath As String)
On Error GoTo Err_Handler
    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset
    Dim blnTran As Boolean
    
    Dim fileNo As Integer
    Dim idx As Integer
    
    blnTran = False
    
    Set cn = CurrentProject.Connection
    Set rs = New ADODB.Recordset
    
    ' トランザクションの開始
    cn.BeginTrans                   '
    blnTran = True

    rs.Open objTbl.name, cn, adOpenKeyset, adLockOptimistic
    
    ' CSV ファイルからデータを一行ずつ読み込む
    fileNo = FreeFile()
    Open strFilePath For Input As #fileNo
    Do Until EOF(fileNo)
        Line Input #fileNo, strLine
        strAry = Split(strLine, ",")
        
        ' データを列ごとに追加する
        rs.addnew
        
        idx = 0
        For Each col In objTbl.cols
            rs(col) = strAry(idx)
            idx = idx + 1
        Next
        
        rs.Update
    Loop
    Close #intFileNo
    
    ' コミット
    cn.CommitTrans
    blnTran = False
    
Finally:
    If Not rs Is Nothing Then rs.Close
    If Not rs Is Nothing Then cn.Close
    
    Exit Sub
    
Err_Handler:
    ' ロールバック
    If blnTran Then cn.RollbackTrans
    MsgBox "エラーが発生しました: " & Err.Description, vbOKOnly
    
    Resume Finally
End Sub

上記を例えば次のように呼ぶ。

Sub test()
    Dim objTbl As New table
    Dim filePath As String
    
    ' CSV ファイルのパス
    filePath = Application.CurrentProject.Path & "\test.csv"
    
    objTbl.name = "テーブル名"        ' データを追加するテーブルの名前
    objTbl.cols.Add "列名"      ' データを追加するテーブルの列の名前
    
    insert objTbl, filePath
End Sub

 

参考