すぐ使えるADO.NET

【Visual BasicによるADO.NETデータベースプログラミング】

本の紹介

バックナンバー:VB.NETデータベースプログラミング

ADO.NETの基本的なプログラミングを中心に、すぐ使えるサンプルプログラム満載です。




【第34号】

 第34号(2005.11.25発行)
======================================================================
           ★★ VB.NETデータベースプログラミング奮闘記 ★★
----------------------------------------------------------------------
いつもご購読ありがとうございます。ADO.NETの基本的なプログラミングを中
心に掲載しますので、今後ともよろしくお願い申し上げます。

すぐ使えるADO.NET --> サンプルプログラム満載
                      http://park5.wakwak.com/‾weblab/
======================================================================
        ■■ VB.NETワンポイント:メソッドのオーバーロード ■■

VB.NETでは、メソッドをオーバーロードすることができます。引数の数、また
はデータ型、または引数の数とデータ型が異なっていれば、基本クラスや同じ
クラスと同じ名前でメソッドを定義することができます。

オーバーロードされていることを明示的に示すためには、Overloadsキーワー
ドを付加しますが、省略することもできます。ただし、ひとつでもOverloads
を使った場合には、他のオーバーロードメソッドの宣言にもOverloadsを使わ
なければなりません。

もし、既存のメソッドと同一名称で引数の数とデータ型が同じメソッドを宣言
すると、コーディング時に、「同じシグニチャを持つ複数の定義が含まれてい
ます」というエラーになります。

前号で、キー値のレコードの有無を調べるメソッドとして、

Public Function existKeyRecord(ByVal parTableName As String, _
                               ByVal parKeyValue As String) As Boolean

を定義しましたが、今号では、複数キー値のレコードの有無を調べるメソッド
も同名のexistKeyRecordで定義します。引数の数とデータ型が異なっています
ので、同一名称でメソッドを定義してもエラーになりません。

Public Function existKeyRecord(ByVal parTableName As String, _
                               ByVal parKeyfield() As String, _
                               ByVal parKeyValue() As String) As Boolean

----------------------------------------------------------------------
     ■■ データベースアクセスクラスの汎用メソッドについて 3 ■■

今回は、複数フィールドで主キーを構成する値のレコードの有無を調べる汎用
的なexistKeyRecordメソッドを作成します。

キーフィールドの数に合わせて、メソッドを作るのではなく、できるだけ少な
いexistKeyRecordメソッドで対応するようにします。

今回のexistKeyRecordメソッドは、テーブルの複数の主キー値がすべてテキス
ト型のフィールドの場合のメソッドを作成します。引数は、テーブル名、キー
フィールド名の配列、キーフィールドに対応するキー値の配列の3つです。

◆引数のNothing(未設定)チェック
引数のチェックをします。引数がNothing(未設定)のチェックを追加して、
Catch oExcept As myDBIOException で捕捉して、独自のエラーメッセージを
表示できるようにしています。このチェックが無い場合でも、
Catch oExcept As Exception で捕捉することができます。

◆テーブル名チェック
最初に、引数のテーブル名をチェックします。前号と同様です。テーブル名は
コンストラクタで取得したmTableNameListに保管してありますから、引数の
テーブル名がmTableNameListになければ、エラーとして、myDBIOException例
外をスローします。

◆引数の数と主キーフィールド数とのチェック
parKeyfield.Length と schemaTable.Rows.Count が不一致なら、
myDBIOException例外をスローします。
同様に、parKeyValue.Length と schemaTable.Rows.Count が不一致なら、
やはり、myDBIOException例外をスローします。

◆キーフィード名チェック
引数にキーフィード名が追加されましたので、キーフィールド名のチェックを
追加します。 第32号で紹介しましたcon.GetOleDbSchemaTableメソッドを使い
ます。

  Dim schemaTable As DataTable
  schemaTable = mConn.GetOleDbSchemaTable( _
                OleDbSchemaGuid.Primary_Keys, _
                New Object() {Nothing, Nothing, parTableName})

DataTable型のschemaTableに主キーに関するスキーマ情報が格納されます。
行の4番目の項目に主キーのフィールド名がセットされますので、すべての値
をCollection型の変数keyListに追加します。

  For i = 0 To schemaTable.Rows.Count - 1
    keyList.Add(schemaTable.Rows(i).Item(3).ToString)
  Next i

このリストと引数のフィールド名配列の値を比較して、エラーチェックをしま
す。引数のフィールド名がkeyListになければ、エラーとして、
myDBIOException例外をスローします。

◆キー値のチェック
キー値のチェックは、まず前後の空白を除去します。そして正規表現Regexク
ラスのIsMatchメソッドを使って、数字、英大文字、英小文字、"_"、"-"以外
の文字が含まれていれば、エラーとします。これは前号と全く同じです。

◆SQL文のWHERE句の構築
生成するSQL文は次のようになります。
  mCommand.CommandText = _
  "SELECT COUNT(*) FROM parTableName  _
   WHERE parKeyfield(0) = @Key0 AND parKeyfield(1) = @Key1"

parTableName、parKeyfield(0)、parKeyfield(1)は引数の値を使い、
@Key0と@Key1、及びANDは、固定文字列を使って、連結していきます。

キーフィールドの数だけループして、WHERE句を完成させます。
まず、"SELECT COUNT(*) FROM" + parTableName + "WHERE " を生成します。
次に、 parKeyfield(i) + "= @Key" + i.ToString + "AND " を連結します。
最後に parKeyfield(i) + "= @Key" + i.ToString を連結すれば完成します。
iはループカウンタの値で、0と1です。

◆レコード件数取得
SQL文が完成したら、mCommandオブジェクトのCommandTextプロパティにセット
し、ExecuteScalarメソッドを呼び出して、キー値に一致するレコード件数を
問合せます。

  Dim Count As Integer = CInt(mCommand.ExecuteScalar())

取得したレコード件数で、キー値レコードの有無をチェックします。

次号では、主キーが1フィールドのテーブルから引数に指定したテーブルの
キー値のレコード1行を取得する汎用的なメソッドgetKeyRecordメソッドをこ
のクラスに追加します。

--【プログラムソースリスト】------------------------------------------
Option Explicit On

Imports System.Data.OleDb
Imports System.Text.RegularExpressions

'----------------- << データベースアクセスクラス >> -----------------
Public Class clsDBIO

  '--------------------< メンバ:変数 >--------------------
  'コネクション
  Private mConn As OleDbConnection
  'コマンド
  Private mCommand As OleDbCommand
  'テーブル名コレクション
  Private mTableNameList As New Collection()

  '*******************************************************************
  ' 機能:コンストラクタ
  ' 引数:なし
  '*******************************************************************
  Public Sub New()

    Try
      'DB接続文字列の設定
      mConn = New OleDbConnection()
      mConn.ConnectionString = _
      "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" _
      & Application.StartupPath & "¥sample.mdb"

      'コネクションオブジェクトの設定
      mCommand = New OleDbCommand()
      mCommand.Connection = mConn

      '********** << テーブル名を取得 >> **********
      Dim schemaTable As DataTable

      mConn.Open()

      schemaTable = mConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, _
                    New Object() {Nothing, Nothing, Nothing, "TABLE"})

      'メンバmTableNameListにテーブル名をセット
      Dim i As Integer
      For i = 0 To schemaTable.Rows.Count - 1
        mTableNameList.Add(schemaTable.Rows(i)("TABLE_NAME").ToString)
      Next i

      mConn.Close()

    Catch oExcept As Exception
      Throw New Exception _
      ("clsDBIOのコンストラクタで例外発生" + oExcept.ToString)

    End Try

  End Sub

  '*******************************************************************
  ' 機能:キー値のレコードの有無を調べるメソッド
  ' 引数:テーブル名、キー値
  ' 戻値:ある-->True、ない-->False
  ' 備考:キー値は英数字 "_" "-" で構成されていること
  '*******************************************************************
  Public Function existKeyRecord( _
    ByVal parTableName As String, ByVal parKeyValue As String) As Boolean

    '第33号を参照願います。

  End Function

  '*******************************************************************
  ' 機能:複数キー値のレコードの有無を調べるメソッド
  ' 引数:テーブル名、キーフィールド名配列、キー値配列
  ' 戻値:ある-->True、ない-->False
  ' 備考:キー値は英数字のみで構成されている
  '*******************************************************************
  Public Function existKeyRecord(ByVal parTableName As String, _
                                 ByVal parKeyfield() As String, _
                                 ByVal parKeyValue() As String) As Boolean

    Dim keyList As New Collection()
    Dim retBool As Boolean                      'リターン値
    Dim i As Integer

    Try

      '引数未設定チェック
      If parTableName = Nothing Then
        Throw New myDBIOException("引数テーブル名が未設定")
      End If
      If parKeyfield Is Nothing Then
        Throw New myDBIOException("引数主キーフィールドが未設定")
      End If
      If parKeyValue Is Nothing Then
        Throw New myDBIOException("引数主キー値が未設定")
      End If

      'テーブル名チェック
      Dim tblName As String
      Dim existFlg As Boolean

      For Each tblName In mTableNameList
        If tblName = parTableName Then
          existFlg = True
          Exit For
        End If
      Next tblName

      If Not existFlg = True Then
        Throw New myDBIOException("テーブル名不正")
      End If

      'DB接続を開く
      mConn.Open()

      '主キーを取得
      Dim schemaTable As DataTable

      schemaTable = mConn.GetOleDbSchemaTable( _
                    OleDbSchemaGuid.Primary_Keys, _
                    New Object() {Nothing, Nothing, parTableName})

      '主キーフィールド数チェック
      If Not parKeyfield.Length = schemaTable.Rows.Count Then
        Throw New myDBIOException( _
        "引数の主キー数がテーブルの主キー数と不一致")
      End If

      '主キー値数チェック
      If Not parKeyValue.Length = schemaTable.Rows.Count Then
        Throw New myDBIOException( _
        "引数の主キー値数がテーブルの主キーフィールド数と不一致")
      End If

      For i = 0 To schemaTable.Rows.Count - 1
        keyList.Add(schemaTable.Rows(i).Item(3).ToString)
      Next i

      Dim wherePhrase As String
      Dim paraStr As String
      Dim keyName As String

      mCommand.Parameters.Clear()

      For i = 0 To schemaTable.Rows.Count - 1

        existFlg = False
        For Each keyName In keyList
          If keyName = parKeyfield(i) Then
            existFlg = True
            Exit For
          End If
        Next keyName

        If Not existFlg = True Then
          Throw New myDBIOException( _
          (i + 1).ToString + "番目のキーフィールド名不正")
        End If

        'キー値チェック(注:キー値は英数字と_と-で構成されている場合)
        parKeyValue(i) = parKeyValue(i).Trim()
        If Not Regex.IsMatch(parKeyValue(i), "^[0-9a-zA-Z_¥-]+$") Then
          '英数字以外はエラー
          Throw New myDBIOException( _
          (i + 1).ToString + "番目のキー値が正しくありません")
        End If

        paraStr = "@key" + i.ToString
        wherePhrase += " " + parKeyfield(i) + "=" + paraStr
        'WHERE句をANDで区切る
        If Not i = schemaTable.Rows.Count - 1 Then
          wherePhrase += " AND "
        End If

        '***** SQL文の引数設定 *****
        mCommand.Parameters.Add( _
          New OleDbParameter(paraStr, OleDbType.Char))

        '----------< コマンドパラメータに値を設定 >----------
        mCommand.Parameters(paraStr).Value = parKeyValue(i)

      Next i

      'SQL文設定
      mCommand.CommandText = _
      "SELECT COUNT(*) FROM " + parTableName + " WHERE" + wherePhrase

      'レコード件数取得
      Dim Count As Integer = CInt(mCommand.ExecuteScalar())

      '----------< 戻値を設定 >----------
      If Count = 1 Then
        retBool = True
      Else
        retBool = False
      End If

    Catch oExcept As myDBIOException
      Throw New myDBIOException(oExcept.Message)
    Catch oExcept As Exception
      Throw New Exception _
      ("clsTableSyainのexistKeyRecordで例外発生" + oExcept.ToString)

    Finally
      'DB接続を閉じる
      If Not mConn Is Nothing Then
        If mConn.State = ConnectionState.Open Then
          mConn.Close()
        End If
      End If

    End Try

    '◆リターン
    Return retBool

  End Function

End Class

'--------------- << 独自エラーメッセージ用例外クラス >> --------------
Public Class myDBIOException
  Inherits ApplicationException

  Public Sub New(ByVal errorMessage As String)
    MyBase.New(errorMessage)
  End Sub

End Class

----------------------------------------------------------------------
            ■■ 次号予告 第35号(12月16日発行予定) ■■
1. VB.NETワンポイント
2. データベースアクセスクラスの汎用メソッドについて 4
======================================================================
VB.NET データベースプログラミング奮闘記
  発行者:ウェブ実験室(-----@-----)
          http://park5.wakwak.com/‾weblab/
----------------------------------------------------------------------
このメールマガジン(マガジンID: 0000128094)は、
インターネットの本屋さん『まぐまぐ』から配信されています。
  http://www.mag2.com/

【購読中止の方法】購読の中止は次のホームページからお願い致します。
  http://park5.wakwak.com/‾weblab/
  http://www.mag2.com/m/0000128094.htm
----------------------------------------------------------------------
このメールマガジン及び、「すぐ使えるADO.NET」ホームページで公開してい
るソースプログラム・データの利用により生じた損害等については、発行者は
一切責任を負いません。
ソースプログラムの再利用は自由です。著作権は発行者が所有します。
このメールマガジン及び、「すぐ使えるADO.NET」ホームページに掲載されて
いる会社名・製品名等は、各社の登録商標または商標です。
======================================================================

Copyright© すぐ使えるADO.NET. All rights reserved.