2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.NET アプリでデータベースに接続するのさらに続き

Last updated at Posted at 2024-11-02

はじめに

自分は仕事で Oracle データベースに接続する .NET アプリを書いています。と言っても、前任から引継したプログラムを改修しているので、データベースに接続するコードを自分で書いたことはありません。
客先の環境でエラー発生してデータベースに接続できないと、不具合の報告を貰うことがあります。同じプログラムが開発環境や別の端末で正しく動作するので、環境に依存するようです。
どんな環境は OK で、どんな環境は NG なのか、分からなくて苦しみました。当時の試行錯誤を、改めて確認しておこうと思いました。

Oracle.DataAccess.Client を使ってデータベースに接続する

前回の記事 で、System.Data.OracleClient または Oracle.ManagedDataAccess.Client を使ってデータベースに接続するプログラムを書きました。
仕事で引継したプログラムは、Oracle.DataAccess.Client を使ってデータベースに接続するようになっていました。

.NET Framework+Oracle.DataAccess.Client で接続する

.NET Framework アプリを作って Oracle データベースに接続してみます。

参考:【C#】【Oracle】Oracle.DataAccess.dllを利用してデータを取得。その1 | 創造的プログラミングと粘土細工

Visual Studio で「新しいプロジェクトの作成」して「コンソールアプリ (.NET Framework)」を選択します。
フレームワークは .NET Framework 4.5.2 を選択します。

System.Data.OracleClient と違って、Oracle.DataAccess.Client は、.NET Framework に含まれていません。
そこで、Oracle のウェブサイトから接続用ライブラリを入手します。

ODP.NET(管理対象外 )のインストール | 節約プログラマー雑記

その上で、プロジェクトの「参照」に Oracle.DataAccess.Client を追加します。

以下のコードを実行してみます。

using Oracle.DataAccess.Client;
            
string conStr = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)));User id=scott;Password=tiger;";

try
{
    using (OracleConnection cn = new OracleConnection())
    {
        cn.ConnectionString = conStr;
        cn.Open();
        Console.WriteLine("Connected.");
    }
}
catch (Exception ex) {
    Console.WriteLine("Error: " + ex.Message);
}
Console.ReadKey();

動作を確認する環境を用意する

作成した .NET アプリがデータベースに接続できるか確認する環境を用意します。仕事で使用していた環境に近いものを用意しようと思います。

・開発環境
Windows 10
Visual Studio 2017
ODAC 11g および 12c [32 ビット版] および [64 ビット版]

・接続元クライアント機
Windows 10 [64 ビット] および Windows XP [32 ビット]
Oracle Client 11g および 12c [32 ビット版] および [64 ビット版]

・接続先データベースサーバ
Windows 10
Oracle Database 11g XE

ODAC と Oracle Client

Oracle Data Access Components (ODAC) は、一連のWindowsおよび.NETデータ・アクセス・ドライバおよびツールです。.NET、COM および ODBC データ・アクセスのサポート、アプリケーションを開発するための Microsoft Visual Studio ツール、ASP.NET プロバイダ および .NET ストアド・プロシージャ・サポートが含まれます。

ODAC は Oracle が作成して配布しています。Oracle Client を入手してインストールすることで、開発機やクライアント機に導入できます。

Oracle Database 12c Client インストール - Project Group

開発機を準備する

開発機で、.NET アプリに組込する ODAC ライブラリは以下を切替して確認したい。

  • 11g [32 ビット版]
  • 11g [64 ビット版] ←今回は使わない
  • 12c [32 ビット版]
  • 12c [64 ビット版]

「OUI(Oracle Universanl Installer) 版」にしても「XCOPY 版」にしても、インストール先の Windows 環境の GAC やレジストリを更新する。一旦インストールすると、アンインストールしても Windows 環境の変更が完全に戻らない。
Oracle Client がインストールされたことのない Windows が、上記のパターンだけ欲しくなる。

実機を揃えるわけにはいかないし、クラウドサービスの仮想マシンを使ってもよかったのだが、1台の開発機で済ませてみた。
ODAC のライブラリ(実態は DLL ファイル)を、.NET アプリの「参照」に設定できればいいわけだ。
「XCOPY 版」のパッケージ(実態は ZIP ファイル)をダウンロードして解凍する。インストーラを使うとレジストリなど書込されてしまうので、解凍した内容をそのまま使う。
上記のパターンごとに 4 つのフォルダを用意して、使用したいライブラリを「参照」設定する。

クライアント機を準備する

接続元のクライアント機で、Oracle Client は以下を切替して確認したい。

  • 11g [32 ビット版]
  • 11g [64 ビット版]
  • 11g [32 ビット版]+[64 ビット版] 混在 ←今回は使わない
  • 12c [32 ビット版]
  • 12c [64 ビット版]
  • 12c [32 ビット版]+[64 ビット版] 混在

Oracle Client は、一旦インストールすると、アンインストールしても Windows 環境の変更が完全に戻らない。
Oracle Client がインストールされたことのない Windows が、上記のパターンだけ欲しくなる。

実機を揃えるわけにはいかないので困っていたが、Windows サンドボックス が使えるのでないかと思った。

Windows Sandboxを積極的に活用しよう|Kernel

ところが困ったことに、サンドボックスで起動した Windows で Oracle Client のインストーラを起動すると、「インストーラの検証実行に必要な最初の手順が失敗しました」エラーになってインストールできない。

Windows10にOracle Clientをインストールするとき詰まった話 #oracle - Qiita

サンドボックスの Windows アカウントは管理者権限がないのが問題のようだ。

実機を揃えるわけにはいかないので、クラウドサービスの仮想マシンを使うことにした。

Google Compute Engine を使って利用できる Windows 機は Windows Server なので、使いたかった Windows 10 と厳密に同じでないが仕方ない。

ところがそのせいか、インストーラが途中で落ちる。

(Oracle 12.1.0.2 32bit clientを導入する場合の障害について[2016/01/05])

苦労したが、複数の Oracle Client を導入したクライアント機を用意できた。

Windows XP [32 ビット] のクライアント機は、実機を用意した。

サーバ機を準備する

Oracle データベースをインストールするのは、開発機でもいいかと思ったが、アプリに組込するライブラリに影響するといけないので、別に準備した。
当時の環境は Windows Server 2012 R2 だったが、空いていた Windows 10 機を使った。

Oracle Database 11g は、無償版の Express Edition を使った。

併せて、Oracle Database 21c Express Edition も用意した。
こちらはインストールして途中でエラー表示されたりして非常に時間が掛かった。

参考:OracleDatabase21cExpressEditionをイ... - Yahoo!知恵袋

Oracle Client 11g や 12c で Oracle Database 21c に接続できるか確認してみたが、OK だった。

Oracle.DataAccess.Client でデータベースに接続する①

前述した手順で Oracle データベースに接続する .NET アプリを作成します。

.NET アプリに組込する Oracle.DataAccess ライブラリは 12c [64 ビット版] を選びました。
開発機やクライアント機が [64 ビット] 機 だからです。
接続先のデータベースは 11g ですが、新しいバージョンがいいだろうと考えました。

Oracle.DataAccess 12c [64]+Windows 10 [64]+Oracle Client なし・・①

まず、Oracle Client をインストールしていないクライアント機で実行してみます。

'Oracle.DataAccess.Client.OracleConnection' のタイプ初期化子が例外をスローしました。

動作:×

この .NET アプリは開発機で動作しています。違うのは、開発機は Oracle Client がインストールされていることです。
Oracle.DataAccessOracle.ManagedDataAccess と違って、Oracle データベースと直接接続しないで、OS にインストールされた Oracle Client を呼出しているようです。

Oracle.DataAccess 12c [64]+Windows 10 [64]+Oracle Client 12c [64]・・②

上記のクライアント機に Oracle Client 12c [64 ビット版] をインストールします。

接続できました。

動作:○

説明.png

Oracle.DataAccess.Client でデータベースに接続する②

一部のクライアント機は Windows XP [32 ビット版] が残っていると、顧客に言われました。

Oracle.DataAccess 12c [64]+Windows XP [32]+Oracle Client 12c [32]・・③

クライアント機に導入するのは Oracle Client 12c [32 ビット版] になります。
作成した .NET アプリはそのままで実行してみます。

'Oracle.DataAccess.Client.OracleConnection' のタイプ初期化子が例外をスローしました。

動作:×

Oracle.DataAccess 12c [32]+Windows XP [32]+Oracle Client 12c [32]・・④

.NET アプリに組込するライブラリを [32 ビット版] に変更してみます。

接続できました。

動作:○

Oracle.DataAccess.Client でデータベースに接続する③

大半のクライアント機は Windows 10 [64 ビット版] です。

Oracle.DataAccess 12c [32]+Windows 10 [64]+Oracle Client 12c [32]・・⑤

クライアント機にインストールする Oracle Client を、.NET アプリに組込したライブラリに合わせて 12c [32 ビット版] に変更しました。

ハンドルされていない例外: System.BadImageFormatException: ファイルまたはアセンブリ 'Oracle.DataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342'、またはその依存関係の 1 つが読み込めませんでした。間違ったフォーマットのプログラムを読み込もうとしました。

動作:×

Oracle.DataAccess 12c [32]+Windows 10 [64]+Oracle Client 12c [64]・・⑥

クライアント機にインストールする Oracle Client を、クライアント機に合わせて [64 ビット版] に変更しました。

接続できました。

動作:○

.NET アプリに組込したライブラリとクライアント機に導入する Oracle Client は一致していなくていいのでしょうか。

Oracle.DataAccess.Client でデータベースに接続する④

引継した .NET アプリの一部はサードパーティのライブラリを組込していました。そのライブラリは [32 ビット版] だけで [64 ビット版] が提供されていませんでした。
[32 ビット版] Windows で実行できればいいのですが、[64 ビット版] Windows で実行しないといけません。

プログラムは動作を停止しました。

.NET アプリを [32 ビット] モード で実行すればいいようです。.NET アプリの「ターゲット CPU」の指定が AnyCPU だったものを x86 に変更しました。

.NETにおける64ビットプロセスと32ビットプロセスについて #Windows - Qiita

x86 指定+Oracle.DataAccess 12c [32]+Windows 10 [64]+Oracle Client 12c [64]・・⑦

x86 指定してビルドし直した .NET アプリを実行してみます。

'Oracle.DataAccess.Client.OracleConnection' のタイプ初期化子が例外をスローしました。

動作:×

x86 指定+Oracle.DataAccess 12c [32]+Windows 10 [64]+Oracle Client 12c [32]・・⑧

クライアント機にインストールする Oracle Client を、.NET アプリの実行モードに合わせて [32 ビット版] に変更しました。

接続できました。

動作:○

Oracle.DataAccess.Client でデータベースに接続する⑤

一部の .NET アプリは Windows Server 2003 で実行しないといけなくなりました。

Oracle Client 12c は Windows Server 2003 Server で動作しませんでした。

参考:Oracle Database Clientインストレーション・ガイド12cリリース1(12.1) for Microsoft Windows

Oracle Client 11g なら Windows Server 2003 Server で動作するようです。

参考:Oracle Database Clientインストレーション・ガイド, 11g リリース2 (11.2) for Microsoft Windows

x86 指定+Oracle.DataAccess 12c [32]+Windows 10 [64]+Oracle Client 11g [32]・・⑨

クライアント機にインストールする Oracle Client を 11g にしました。

ハンドルされていない例外: System.BadImageFormatException: ファイルまたはアセンブリ 'Oracle.DataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342'、またはその依存関係の 1 つが読み込めませんでした。間違ったフォーマットのプログラムを読み込もうとしました。

動作:×

x86 指定+Oracle.DataAccess 11g [32]+Windows 10 [64]+Oracle Client 11g [32]・・⑩

.NET アプリに組込するライブラリを、Oracle Client に合わせて 11g に変更しました。

接続できました。

動作:○

x86 指定+Oracle.DataAccess 11g [32]+Windows 10 [64]+Oracle Client 12c [32]・・⑪

クライアント機にインストールする Oracle Client を 12c に戻してみました。

接続できました。

動作:○

Oracle.DataAccess.Client でデータベースに接続する⑥

上記のクライアント機で Oracle Client が 32 ビット版 に加えて 64 ビット版 が必要になりました。
Microsoft Access で ODBC 経由で Oracle データベースに接続しているそうです。Access が 32 ビット版 のときは Oracle Client(それに含まれる ODBC ドライバ)は 32 ビット版 が必要で、Access が 64 ビット版 になると ODBC ドライバ 64 ビット版 が必要になるそうです。

参考:雑学の箱 | みどり情報技術

x86 指定+Oracle.DataAccess 11g [32]+Windows 10 [64]+Oracle Client 12c [32]+[64]・・⑫

Oracle Client 32 ビット版64 ビット版 が混在する環境になりました。

接続できました。

動作:○

x86 指定+Oracle.DataAccess 11g [32]+Windows 10 [64]+Oracle Client 12c [32]+[64]←64 指定・・⑬

別のアプリがデータベースに接続できなくなったと顧客から報告ありました。調べたところ ORACLE_HOME の指定すれば直るようです。

Oracle 接続できない…よくある事例と対処法

Oracle Client [64 ビット版] のインストール先を ORACLE_HOME に指定しました。

ORA-12557: TNS: プロトコル・アダプタをロードできません

動作:×

x86 指定+Oracle.DataAccess 11g [32]+Windows 10 [64]+Oracle Client 12c [32]+[64]←32 指定・・⑭

Oracle Client [32 ビット版] のインストール先を ORACLE_HOME に指定しました。

接続できました。

動作:○

x86 指定+Oracle.DataAccess 11g [32]+Windows 10 [64]+Oracle Client 12c [64]・・⑮

.NET アプリに組込するライブラリは [32 ビット版] +クライアント機の Oracle Client は [64 ビット版] で OK でした(上記⑥)。[x86] 指定 した .NET アプリは、どうなるでしょうか。

'Oracle.DataAccess.Client.OracleConnection' のタイプ初期化子が例外をスローしました。

動作:×

.NET アプリが [32 ビット] モード で実行されるなら、呼出される Oracle Client は [32 ビット版] でなければならないようです。

確認の結果のまとめ

以上の試行錯誤を表にまとめてみます。

Oracle.DataAccess OS Oracle client 動作
AnyCPU 12c [64] Windows 10 [64] なし ×
AnyCPU 12c [64] Windows 10 [64] 12c [64]
AnyCPU 12c [64] Windows XP [32] 12c [32] ×
AnyCPU 12c [32] Windows XP [32] 12c [32]
AnyCPU 12c [32] Windows 10 [64] 12c [32] ×
AnyCPU 12c [32] Windows 10 [64] 12c [64]
x86 12c [32] Windows 10 [64] 12c [64] ×
x86 12c [32] Windows 10 [64] 12c [32]
x86 12c [32] Windows 10 [64] 11g [32] ×
x86 11g [32] Windows 10 [64] 11g [32]
x86 11g [32] Windows 10 [64] 12c [32]
x86 11g [32] Windows 10 [64] 12c [32]+[64]
x86 11g [32] Windows 10 [64] 12c [32]+[64]←64 ×
x86 11g [32] Windows 10 [64] 12c [32]+[64]←32
x86 11g [32] Windows 10 [64] 12c [64] ×

ルールが分かってくればまだしも当時は分かっていなかったので、作成している .NET アプリと別の都合で実行環境が変化するたびにデータベースに接続できなくなって、対応に悩まされました。

Oracle.ManagedDataAccess.Client を使って接続する

Oracle.DataAccess ライブラリを使うと上記のように、インストールする Oracle Client の状況に依存して、同じ .NET アプリが接続できたりできなくなったりします。
これを回避するために、どうしたらいいでしょうか。

Oracle.ManagedDataAccess ライブラリを使えばいいようです。

【.net】Oracleクライアントインストールなしで接続する方法 | 水戸スヤのSE備忘録

Oracle.ManagedDataAccessOracle.DataAccess と違って、OS にインストールされた Oracle Client を使わずに、Oracle データベースと直接接続するようです。

引継したプログラムが Oracle.DataAccess ライブラリを使っていたので、そのまま使い続けてしまいましたが、Oracle.ManagedDataAccess ライブラリに切替するのは、簡単だったようです。

ODP.NET Managed Driver(管理対象ドライバ)についての私的まとめ - しばたテックブログ

接続先を記述する

前回の記事 で、接続先などを指定する接続文字列は以下のように書いています。

string conStr = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)));User id=scott;Password=tiger;";

参考:ODP.NET の接続文字列 - tsucchi’s diary(元はてなダイアリー)

仕事で引継したプログラムを見ると、Data Source は上記のように書かれていませんでした。

string conStr = "Data Source=ORCL;User id=scott;Password=tiger;";

ここで指定された ORCL では接続先が特定できません。これは「ネットサービス名」で、別途 tnsnames.ora ファイルに設定を記述しておいて、ライブラリが設定された内容を読みます。

参考:tnsnames.oraと接続文字列の関係 #oracle - Qiita

tnsnames.ora
ORCL = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL)))

これでは見づらいのでインデントします。

tnsnames.ora
ORCL = 
    (DESCRIPTION =
        (ADDRESS_LIST =
            (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
        )
        (CONNECT_DATA =
            (SERVICE_NAME = ORCL)
        )
    )

この tnsnames.ora は、どこに置けばいいのでしょうか。

Oracle Client をインストールして Net Manager ツールを使うと、GUI で tnsnames.ora を所定の場所に作成してくれます。.NET アプリの Oracle Client ライブラリは、その場所に保存された tnsnames.ora を読んでくれるようです。
ただし、Oracle Client を複数インストールすると、どの設定が読まれるのか、にわかに分からなくなります。

参考:【考察】Oracle Clientを何度もインストールするとどこのtnsnames.oraを使っているかわからなくなるという話 #Windows - Qiita

tnsnames.ora ファイルは、.NET アプリの実行ファイルと同じフォルダに置けば、それが読込されます。

参考:Managed な ODP.NET で tnsnames.ora を参照する (Windows, Visual Studio 2015) #oracle - Qiita

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?