Edited at

VB .NET:Oracle のバージョンに左右されない接続方法

この記事は Visual Basic Advent Calendar 2018 の 23日目の記事です。


DB のバージョンに左右される現場の例

エンプラ系で VB.NET + Oracle を採用している場合、妙な環境で開発されている方も多いのではないかと思います。

例えば、


  • 開発環境と本番環境で、Oracleのバージョンが違う(bit数も違ってたり)

  • 開発者全員が、同一の環境を用意していない

など。

本番直前のタイミングで

「あ、開発は11でやってもらったけど、本番環境はバージョン12で動かすからねー。」とか言われて、正気を保てなくなったエンジニアも何人か居るんじゃないかと思います。

(開発環境は過去のものを使いまわして、本番環境はアップデートしているというパターン。当然、メンバーには周知されていない。)

そこまでダメな事例を出さずとも、バージョンが上がるたびに ODBCのバージョンを変えたり、

参照設定を変えたりするのが面倒くさいと感じる方も多いのではないかと思います。

ODBC固有の機能を使用しているわけでもなく、ORマッパーも使用しておらず、ゴリゴリと生SQLを書いているだけなら、別に参照設定して Oracle専用のドライバを指定せずとも、DBへの接続が可能です。

具体的には、DbProviderFactories という、抽象化されたクラスを使用します。


コーディング例:プロバイダー側

Imports System.Data.Common

Imports System.Data

Public Class DataAccess
Implements IDisposable

Private conn As DbConnection = Nothing
Private factory As DbProviderFactory = Nothing
Private tran As DbTransaction = Nothing
Private _hasAccessError As Boolean = False
Private _hasSQLError As Boolean = False
Private _errorMessage As String = String.Empty
Private _sqlContents As String = String.Empty
Private isDisposed As Boolean = False

Public Sub New()
Dim dcsb As DbConnectionStringBuilder

Try
_hasAccessError = False

factory = DbProviderFactories.GetFactory("Oracle.DataAccess.Client")
dcsb = factory.CreateConnectionStringBuilder
dcsb("Data Source") = ConfigurationManager.AppSettings("dataSource")
dcsb("User ID") = ConfigurationManager.AppSettings("userId")
dcsb("Password") = ConfigurationManager.AppSettings("pass")

conn = factory.CreateConnection()
conn.ConnectionString = dcsb.ConnectionString

conn.Open()
tran = conn.BeginTransaction()
_hasSQLError = False
_errorMessage = String.Empty

Catch ex As Exception
_hasAccessError = True
_errorMessage = ex.Message

End Try

End Sub

Public Function ExcuteQuery(ByVal SQLContents As String) As DataSet

Dim cmd As DbCommand
Dim da As DbDataAdapter
Dim ds As DataSet = New DataSet

Try
_hasSQLError = False
_sqlContents = SQLContents
cmd = conn.CreateCommand
cmd.CommandText = SQLContents

da = factory.CreateDataAdapter()
da.SelectCommand = cmd
da.Fill(ds)

Catch ex As Exception
_hasSQLError = True
_errorMessage = ex.Message

End Try

Return ds

End Function

Public Function ExecuteNonQuery(ByVal SQLContents As String, Optional ByVal isCommit As Boolean = True) As Integer

Dim cmd As DbCommand
Dim affectedRows As Integer = 0

Try
_hasSQLError = False
_sqlContents = SQLContents
cmd = conn.CreateCommand
cmd.CommandType = CommandType.Text
cmd.CommandText = SQLContents

affectedRows = cmd.ExecuteNonQuery()
If isCommit Then
Commit()
End If

Catch ex As Exception
_hasSQLError = True
_errorMessage = ex.Message
Rollback()

End Try

Return affectedRows

End Function

Public Sub Commit()
Try
tran.Commit()
tran = conn.BeginTransaction()
Catch ex As Exception
End Try
End Sub

Public Sub Rollback()
Try
tran.Rollback()
tran = conn.BeginTransaction()
Catch ex As Exception
End Try
End Sub

End Class

Dispose や Finalize 、他色々と省略しています。


コーディング例:プロバイダー側の設定

web.config に設定内容を記述します。

<configuration>

<appSettings>
<add key="dataSource" value="YOUR_SCHEMA" />
<add key="userId" value="SYSTEM" />
<add key="pass" value="SYSTEM" />
</appSettings>
</configuration>


コーディング例:使用側

  Using dbAccess As New DataAccess

ds = dbAccess.ExcuteQuery("SELECT * FROM users")

affectedRows = dbAccess.ExecuteNonQuery("UPDATE projects SET status=1")

End Using

端折りすぎてますが、雰囲気だけ伝わればいいかなぐらいで書いてます。

ちゃんと書くと長いんで。


解説

プロバイダー側の以下のコードにて、DB接続のオブジェクトを生成しています。

factory = DbProviderFactories.GetFactory("Oracle.DataAccess.Client")

端末に OracleClientがインストールされていれば、勝手にデフォルトで使用するバージョンを拾って、

後はよしなにやってくれます。

(10g がインストールされている端末では 10gの Clientを見つけ出し、11g がインストールされている端末では、11g の Clientを探し出す。)

なので、Oracle Client さえインストールされていれば、コネクション設定をこねくり回す必要もなくなっています。

Oracle Server をインストールすると、Oracle Clientも自動でインストールされるので、どちらで動かす場合も問題ないかと思われます。

また、引数に "Oracle.DataAccess.Client" を渡して Oracle接続用のオブジェクトを生成していますが、

恐らく、SQLServer や MySQL でも同じ方法で行けるんじゃないかと思います。

余談ですが、上記の「Factory」は、多分、デザインパターンにおける Facory Method の事。