ODP.NET (Oracle Data Provider for .NET)
Visual Basic(VB6.0A)からOracleへアクセスする方法として oo4o を使った内容を以前から載せてはいましたが、
時代はVB.NETでの開発となり、ADO.NET の方式が主流となってきました。
ADO.NET とは、SQL Server や XML などのデータソースや、OLE DBやODBC経由でデータ ソースに対する一貫性を持ったアクセスができる仕組みです。
オラクルも「.NET」に対応するために、ネイティブにデータベースにアクセスできる「Oracle Data Provider for .NET」(ODP.NETと略します)を提供しています。
基本的な関数などはADO.NETと似た部分が多いですが、オラクル独自の機能が使用可能です。
ODP.NET使用の準備
ODP.NETを使用するためには、Oracle Clientをインストールするのがいいのですが、
.NETからデータベースへのアクセスのみを行いたい場合はOracle Data Access Components のインストールで十分です。
オラクルの
「Oracle Data Access Components (ODAC) for Windows ダウンロード」
ページから該当するダウンロードを選びます。
私は32ビット用の
「32-bit ODAC with ODT ダウンロード」
を選びました。
このページを見ますと多くのバージョンがダウンロードできますが、私はオラクルサーバのバージョンに合わせて
ODAC 11.2 Release 5 and Oracle Developer Tools for Visual Studio (11.2.0.3.20)をダウンロードしました。
■「ODTwithODAC1120320_32bit.zip」をダウンロードし、デスクトップZIPファイルを解凍します。
■「setup.exe」を実行し、順次画面に従い必要な項目を入力しながら進めます。
ほぼ以下の画像の設定の様に進めればインストールが終了します。(画面は左から右へ、上から下に進みます)
■インストール後「C:\oracle」フォルダに登録されていることを確認します。
オラクルへのアクセスに必要なものは「C:\oracle\odp.net\bin\2.x\Oracle.DataAccess.dll」です。
(.NET4の場合には「C:\oracle\odp.net\bin\4\Oracle.DataAccess.dll」です。)
■VisualStudioでの参照設定
ソリューションエクスプローラの中の参照設定で、「参照の追加」を行います。
参照の追加のダイアログで、「参照」タブの中から、「C:\oracle\odp.net\bin\2.x\Oracle.DataAccess.dll」を設定します。
これで、VB.NET から ODP.NET を利用する準備ができました。
Oracleへの接続と切断
Orcaleへの接続と切断のみの処理を、フォームに貼り付けたコマンドボタンのクリックイベントでテストします。
ODP.NETを使うためには「Oracle.DataAccess.Client」をソースの先頭で宣言したほうが良いでしょう。
接続のために、Orcaleの接続用オブジェクトの OracleConnection を使用します。
OracleConnection に接続文字列を渡して、オブジェクトの生成を行っています。
■簡易接続ネーミング・メソッドを使用した接続文字列について
//<ホスト名>[:<ポート番号>][/<データベース名(SID)>]
(ポート番号省略時は”:1521”が指定されたものとする)
Instant Clientのtnsnames設定(tnsnames.oraファイル)を構成することなく、アプリケーションから直接データベースに対する接続文字列を指定できます。
ソース内でコメントの接続文字列は、プログラムをサーバ上で動作させる場合で、
localhost の設定でOKです。
02 | Imports Oracle.DataAccess.Client |
06 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
08 | Dim strConnect As String = _ |
09 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
13 | Dim Conn As New OracleConnection(strConnect) |
オラクル接続オブジェクト OracleConnection のメソッド Open・Close を使用して接続のオープン・クローズを行います。
簡単な接続はこれでいいのですが、実際にはエラー処理が必要になります。
VB.NET ではエラー処理に Try...Catch...End Try ブロック構造を使用します。
ODP.NETにはエラーが発生したときに Catch でスローされる OracleExceptionクラスがありますので、これを使った例を以下に示します。
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test2;" |
07 | Dim Conn As New OracleConnection(strConnect) |
13 | Catch exora As OracleException |
15 | MsgBox(exora.Number & ":" & exora.Message) |
上記の例では、エラーを起こすためにパスワードを間違ったものにしています。
このプログラムを実行すると、以下のメッセージが表示されます。
SQLの実行その1:簡単なSELECT文の実行
データベース内のデータを検索するSQL文としてのSELECT文の実行を行います。
ここでは簡単なSELECT文として、DUAL擬似表からシステム日付を取得する処理を示します。
ODP.NET では以下のオブジェクトを使用しテーブルからのデータを取得します。
オブジェクト名 |
概要 |
備考 |
OracleConnection |
データベースへの接続オブジェクト |
データベース接続文字列を渡して接続処理を行う |
OracleCommand |
データベースに対して実行する SQL ステートメントまたは ストアド プロシージャ用オブジェクト |
SQL文と接続オブジェクト渡して SQL文(ストアド・プロシージャまたはテーブル名)と接続オブジェクト渡して、OracleCommandオブジェクトにリクエストをカプセル化します。OracleCommandオブジェクトは、リクエストを作成してデータベースに送信し、結果を戻します。 |
OracleDataReader |
データ行の前方向ストリームを読み取るオブジェクト |
OracleCommandオブジェクトのExecuteReader()メソッドによりOracleDataReaderオブジェクトが返されます。 |
■処理手順
・接続文字列の生成
・オラクル接続オブジェクトの生成
・オラクル接続オープン
・コマンドオブジェクトの生成
・コマンドオブジェクトの実行で読込オブジェクト取得
・データ行の読込処理
・読込が正常の場合、各データの取得
・読込オブジェクトのクローズ
・オラクル接続クローズ
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim Conn As New OracleConnection(strConnect) |
13 | "SELECT SYSDATE, TO_CHAR(SYSDATE, 'YYYY/MM/DD') AS DATEX FROM DUAL" |
15 | Dim Cmd As New OracleCommand(SQL, Conn) |
16 | Cmd.CommandType = CommandType.Text |
18 | Dim dr As OracleDataReader = Cmd.ExecuteReader() |
20 | If dr.Read() = True Then |
22 | MsgBox(dr.Item( "SYSDATE" ) & ":" & dr.Item( "DATEX" )) |
23 | MsgBox(dr.Item(0) & ":" & dr.Item(1)) |
24 | MsgBox(dr(0) & ":" & dr( "DATEX" )) |
25 | MsgBox(dr.GetDateTime(0) & ":" & dr.GetString(1)) |
32 | Catch exora As OracleException |
34 | MsgBox(exora.Number & ":" & exora.Message) |
■注意点
データ行の読込が正常でのデータの取得の所で、4種類の方法を示しています。
取得①
OracleDataReaderオブジェクトのプロパティ Item にカラム名文字列を与えて、カラムの値を取得しています。
取得②
OracleDataReaderオブジェクトのプロパティ Item にカラムIndexを与えて、カラムの値を取得しています。
この場合は、Indexとしては 0 , 1 しか設定できません。
取得③
OracleDataReaderオブジェクトのプロパティ Item はデフォルト・プロパティなので、(C#ではインデクサというらしい)
OracleDataReaderに直接カラム名文字列を与えることで、カラムの値を取得できます。
取得④
OracleDataReader型指定アクセッサを使用してデータ取得を行います。
型指定アクセッサは、Oracleネイティブ・データ型を.NETタイプに変換するメソッドです。
厳密にデータ変換を行いたいのであれば、この方法がベストだと思います。
■代表的な型指定アクセッサについて
Oracleネイティブ・データ型 |
.NETタイプ |
型指定アクセッサ |
BLOB |
System.Byte() |
GetBytes |
CHAR |
System.String
System.Char()
|
GetString
GetChars
|
DATE |
System.DateTime |
GetDateTime |
NUMBER |
System.Decimal
System.Byte
System.Int16
System.Int32
System.Int64
System.Single
System.Double
|
GetDecimal
GetByte
GetInt16
GetInt32
GetInt64
GetFloat
GetDouble
|
NCHAR |
System.String
System.Char()
|
GetString
GetChars
|
VARCHAR2 |
System.String
System.Char()
|
GetString
GetChars
|
NVARCHAR2 |
System.String
System.Char()
|
GetString
GetChars
|
■関連記事
⇒
Oracle SQL SELECT1 : SELECT文の基礎
SQLの実行その2:複数行を返すSELECT文の実行
SQLの実行その1のSELECT文では1行しか結果を返さないことがはっきりしていましたが、
複数行を返すSELECT文を実行することのほうが実際には多いものです。
以下のプログラムでは、TM_商品の商品コードと商品名の一覧を表示する処理を行っています。
「SQLの実行その1」との違いは、読込処理で OracleDataReader.read() の結果が
True ではなくなるまで Whileループ で処理をしているところです。
OracleDataReader.read() は読込む行が無くなると False を返します。
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim Conn As New OracleConnection(strConnect) |
12 | Dim SQL As String = "SELECT 商品コード, 商品名 FROM TM_商品" |
14 | Dim Cmd As New OracleCommand(SQL, Conn) |
15 | Cmd.CommandType = CommandType.Text |
17 | Dim dr As OracleDataReader = Cmd.ExecuteReader() |
18 | Dim strDsp As String = "" |
20 | While (dr.Read() = True ) |
22 | strDsp &= dr.Item( "商品コード" ).ToString & ":" & dr.Item( "商品名" ) & vbCr |
31 | Catch exora As OracleException |
33 | MsgBox(exora.Number & ":" & exora.Message) |
SQLの実行その3:INSERT,UPDATE,DELETE文の実行
SELECT文以外のDML(データ操作言語)であるINSERT,UPDATE,DELETE文の実行を
OracleCommandオブジェクトのメソッドである ExecuteNonQuery を用いて行います。
ExecuteNonQuery の戻り値は処理された行数が返されます。
■1個のINSERT文の実行
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim Conn As New OracleConnection(strConnect) |
13 | "INSERT INTO TM_商品(商品コード, 商品名, 商品区分, 仕入単価, 売上単価)" & _ |
14 | " VALUES(1001,'商品1001', '区分1001', 10000, 15000)" |
16 | Dim Cmd As New OracleCommand(SQL, Conn) |
18 | Dim nCnt As Integer = Cmd.ExecuteNonQuery() |
21 | Catch exora As OracleException |
23 | MsgBox(exora.Number & ":" & exora.Message) |
以下は連続で、INSERT、UPDATE、DELETE文の実行を行います。
上の「1個のINSERT文の実行」でも、以下の例でも、DML文の実行は成功した場合にその都度コミットされています。
■INSERT,UPDATE,DELETE文の実行
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim Conn As New OracleConnection(strConnect) |
13 | "INSERT INTO TM_商品(商品コード, 商品名, 商品区分, 仕入単価, 売上単価)" & _ |
14 | " VALUES(1001,'商品1001', '区分1001', 10000, 15000)" |
16 | Dim Cmd As New OracleCommand(SQL, Conn) |
18 | Dim nCnt As Integer = Cmd.ExecuteNonQuery() |
21 | SQL = "INSERT INTO TM_商品(商品コード, 商品名, 商品区分, 仕入単価, 売上単価)" & _ |
22 | " VALUES(1002,'商品1002', '区分1002', 10000, 15000)" |
26 | nCnt = Cmd.ExecuteNonQuery() |
29 | SQL = "UPDATE TM_商品 SET 売上単価 = 20000 WHERE 商品コード = 1001" |
33 | nCnt = Cmd.ExecuteNonQuery() |
36 | SQL = "DELETE TM_商品 WHERE 商品コード = 1002" |
40 | nCnt = Cmd.ExecuteNonQuery() |
44 | Catch exora As OracleException |
46 | MsgBox(exora.Number & ":" & exora.Message) |
■関連記事
⇒
Oracle SQL・データの追加(INSERT)
⇒
Oracle SQL・データの更新(UPDATE)
⇒
Oracle SQL・データの削除(DELETE)
SQLの実行その4:トランザクションを加味したINSERT,UPDATE,DELETE文の実行
「SQLの実行その3:INSERT,UPDATE,DELETE文の実行」ではDML文の実行の都度コミットがされてしまうので、
途中でエラーが在った場合はそこまでの結果がデータに残ってしまいます。
そこで、トランザクション処理をDML文の実行の前後で掛けてやれば、エラーが在った場合には更新処理が反映されません。
以下の例では、OracleConnectionオブジェクトのBeginTransactionメソッドを用いて、
トランザクション開始しOracleTransactionオブジェクトを取得します。
OracleCommandオブジェクトにOracleTransactionオブジェクトを関連付けた後で、DML文の実行を行います。
各DML文の実行が正常に終わった後に、OracleTransactionオブジェクトのCommitを行って、全てのDML文の確定を行います。
尚、オラクルエラーやプログラムエラーが在った場合には、OracleTransactionオブジェクトのRollbackを行って、
全てのDML文の結果の反映を廃棄を行います。
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim Conn As New OracleConnection(strConnect) |
09 | Dim Trans As OracleTransaction = Nothing |
14 | Trans = Conn.BeginTransaction(IsolationLevel.ReadCommitted) |
18 | "INSERT INTO TM_商品(商品コード, 商品名, 商品区分, 仕入単価, 売上単価)" & _ |
19 | " VALUES(1001,'商品1001', '区分1001', 10000, 15000)" |
21 | Dim Cmd As New OracleCommand(SQL, Conn) |
23 | Cmd.Transaction = Trans |
25 | Dim nCnt As Integer = Cmd.ExecuteNonQuery() |
28 | SQL = "INSERT INTO TM_商品(商品コード, 商品名, 商品区分, 仕入単価, 売上単価)" & _ |
29 | " VALUES(1002,'商品1002', '区分1002', 10000, 15000)" |
33 | nCnt = Cmd.ExecuteNonQuery() |
36 | SQL = "UPDATE TM_商品 SET 売上単価 = 20000 WHERE 商品コード = 1001" |
40 | nCnt = Cmd.ExecuteNonQuery() |
43 | SQL = "DELETE TM_商品 WHERE 商品コード = 1002" |
47 | nCnt = Cmd.ExecuteNonQuery() |
53 | Catch exora As OracleException |
57 | MsgBox(exora.Number & ":" & exora.Message) |
■関連記事
⇒
トランザクション・ロック
BLOB型の利用方法:画像データをテーブルに設定
■テーブルにBLOB型を設定しその中に画像データファイルを格納する方法を以下に示します。
テストを行うためのBLOBフィールドを持つテーブルを用意します。(以下のCREATE文でテーブルを作成)
2 | ID NUMBER(5,0) primary key, |
画像ファイルはテストのため、「test.png」というファイル名とします。(画像の内容は「Oracleへの接続と切断」でメッセージとして表示しているものです)
このファイルを全てバイト配列に読込み、その値を全てBLOBフィールドに登録します。
INSERT文の定義の文字列の中で「:blob」がありますが、コマンドオブジェクトを生成した後でこの引数名で値を設定できます。
というよりもBLOB型のフィールドにはSQL文で直接記述できないためこの方法を用います。
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim fs As New System.IO.FileStream( "test.png" , IO.FileMode.Open, IO.FileAccess.Read) |
08 | Dim blob(fs.Length) As Byte |
09 | fs.Read(blob, 0, fs.Length) |
11 | Dim Conn As New OracleConnection(strConnect) |
16 | Dim SQL As String = "INSERT INTO TT_BLOB(ID, BLOB) VALUES(1, :blob)" |
18 | Dim Cmd As New OracleCommand(SQL, Conn) |
20 | Dim prm As OracleParameter = Cmd.Parameters.Add( "blob" , OracleDbType.Blob) |
24 | Dim nCnt As Integer = Cmd.ExecuteNonQuery() |
27 | Catch exora As OracleException |
29 | MsgBox(exora.Number & ":" & exora.Message) |
■BLOBデータを取得し表示
上で登録されたBLOBデータを読込んで、フォーム上のPictureBoxに設定し表示します。
SELECT文でBLOBデータのカラムを指定し、コマンドオブジェクトを生成後、OracleDataReaderで読み込み処理を行います。
OracleDataReader の GetOracleBlob メソッドでBLOBデータの取得を行い、MemoryStreamオブジェクトに変換後、
PictureBoxに画像設定を行います。
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim Conn As New OracleConnection(strConnect) |
12 | Dim SQL As String = "SELECT BLOB FROM TT_BLOB WHERE ID = 1" |
14 | Dim Cmd As New OracleCommand(SQL, Conn) |
15 | Cmd.CommandType = CommandType.Text |
17 | Dim dr As OracleDataReader = Cmd.ExecuteReader() |
21 | Dim blob As Oracle.DataAccess.Types.OracleBlob = dr.GetOracleBlob(0) |
23 | Dim mstr As New System.IO.MemoryStream(blob.Value) |
25 | PictureBox1.Image = New Bitmap(mstr) |
32 | Catch exora As OracleException |
34 | MsgBox(exora.Number & ":" & exora.Message) |
■BLOBデータ更新1:OracleCommandおよびOracleParameterを使用したLOBの更新
既に存在するBLOBデータを更新する方法は、新規追加の場合と同じになります。違いはSQL文がUPDATE文である点のみです。
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim fs As New System.IO.FileStream( "test2.png" , IO.FileMode.Open, IO.FileAccess.Read) |
08 | Dim blob(fs.Length) As Byte |
09 | fs.Read(blob, 0, fs.Length) |
11 | Dim Conn As New OracleConnection(strConnect) |
16 | Dim SQL As String = "UPDATE TT_BLOB SET BLOB = :blob WHERE ID = 1" |
18 | Dim Cmd As New OracleCommand(SQL, Conn) |
20 | Dim prm As OracleParameter = Cmd.Parameters.Add( "blob" , OracleDbType.Blob) |
23 | Dim nCnt As Integer = Cmd.ExecuteNonQuery() |
26 | Catch exora As OracleException |
28 | MsgBox(exora.Number & ":" & exora.Message) |
■BLOBデータ更新2:ODP.NET LOBオブジェクトを使用したLOBの更新
BLOBデータを更新方法のもう一つの方法は、トランザクションを開始し SELECT FOR UPDATE でBLOBデータの行を取得します。
その後、OracleDataReader の GetOracleBlobForUpdate メソッドでBLOBデータ(OracleBlob)そのものを取得します。
OracleBlob の書き込みメソッドを使ってバイト配列を設定してやります。
この処理で一つ注意点があります。SELECT文の中で取得するカラムに PRIMARY KEY を指定しないと、以下のエラーが発生します。
(以下の例では SELECT BLOB, ID FROM ... の中の ID です)
「この操作の選択リストには、PRIMARY KEY、ROWIDまたはUNIQUE NOT NULL列が必要です」
02 | Private Sub Button5_Click( ByVal sender As System. Object , ByVal e As System.EventArgs) Handles Button5.Click |
04 | Dim strConnect As String = _ |
05 | "Data Source=//192.168.1.207/test; User ID=test;Password=test;" |
07 | Dim fs As New System.IO.FileStream( "test.png" , IO.FileMode.Open, IO.FileAccess.Read) |
08 | Dim blobByte(fs.Length) As Byte |
09 | fs.Read(blobByte, 0, fs.Length) |
11 | Dim Conn As New OracleConnection(strConnect) |
13 | Dim Trans As OracleTransaction = Nothing |
18 | Trans = Conn.BeginTransaction(IsolationLevel.ReadCommitted) |
20 | Dim SQL As String = "SELECT BLOB, ID FROM TT_BLOB WHERE ID = 1 FOR UPDATE" |
22 | Dim Cmd As New OracleCommand(SQL, Conn) |
23 | Cmd.CommandType = CommandType.Text |
25 | Cmd.Transaction = Trans |
27 | Dim dr As OracleDataReader = Cmd.ExecuteReader() |
31 | Dim blob As Oracle.DataAccess.Types.OracleBlob = dr.GetOracleBlobForUpdate(0) |
35 | blob.Write(blobByte, 0, blobByte.Length) |
43 | Catch exora As OracleException |
47 | MsgBox(exora.Number & ":" & exora.Message) |
■VB.NET関連記事
⇒
「VB.NET-TIPS」ページ