C#でOracleに接続する方法|ODP.NETの設定から接続エラー対処まで実践解説

はじめに

C#でOracleに接続する方法は、業務システム開発で非常によく使われます。特に、既存の基幹システムや販売管理、在庫管理、会計システムなどではOracle Databaseが採用されているケースが多く、C#アプリケーションから安全かつ安定してOracleに接続する知識は実務で重要です。

C#からOracleへ接続する場合、現在はODP.NET、特にOracle.ManagedDataAccessまたはOracle.ManagedDataAccess.Coreを使う方法が一般的です。NuGetから追加でき、OracleConnectionOracleCommandOracleDataReaderなどのADO.NET標準に近い書き方でOracle Databaseを操作できます。Oracle公式ドキュメントでも、ODP.NET CoreはNuGetで導入できる.NET向けのデータアクセスドライバとして案内されています。

この記事では、C#でOracleに接続するための環境準備、ODP.NETのインストール、接続文字列の書き方、SQL実行コード、よくある接続エラーの原因と対処法まで、実務で使える形で解説します。

1. C#でOracleに接続する前に押さえるべき基本

1-1. C#からOracleへ接続する代表的な方法

C#からOracle Databaseに接続する方法には、主に次のような選択肢があります。

まず代表的なのが、Oracle公式の.NET向けデータプロバイダであるODP.NETを使う方法です。C#でOracle接続を行う場合、基本的にはこのODP.NETを選ぶのが第一候補になります。

そのほかに、ODBCやOleDbを使って接続する方法もあります。ただし、Oracle固有の機能を扱いやすいこと、パフォーマンスやサポート面でOracle向けに最適化されていることを考えると、通常の業務アプリケーションではODP.NETを使うのが無難です。

Entity Framework CoreやDapperなどのORM・マイクロORMを使う場合でも、内部的にはOracle向けのプロバイダを利用します。そのため、C#でOracleを扱う基礎として、まずODP.NETによる接続方法を理解しておくことが重要です。

1-2. ODP.NETとは何か

ODP.NETは、Oracle Data Provider for .NETの略で、Oracle Databaseに.NETアプリケーションから接続するためのデータプロバイダです。C#からOracleに接続し、SQLを実行したり、ストアドプロシージャを呼び出したり、トランザクションを制御したりできます。

ODP.NETを使うと、C#側では次のようなクラスを利用します。

C#
OracleConnection
OracleCommand
OracleDataReader
OracleParameter
OracleTransaction

これらはADO.NETの考え方に沿っており、SQL ServerのSqlConnectionSqlCommandを使ったことがある人であれば、比較的理解しやすい構成です。

ODP.NETには、.NET Framework向け、.NET Core/.NET 5以降向け、管理対象ドライバ、管理対象外ドライバなど複数の種類があります。新規開発では、対象の.NETバージョンに合ったNuGetパッケージを選ぶことが大切です。

1-3. Oracle.ManagedDataAccessとOracle.DataAccessの違い

C#でOracle接続を調べると、Oracle.ManagedDataAccessOracle.DataAccessという名前を見かけることがあります。両者の違いを理解しておかないと、接続エラーやビルドエラーの原因になります。

Oracle.ManagedDataAccessは、管理対象ドライバです。C#アプリケーション側にNuGetパッケージを追加して利用でき、基本的にはOracle ClientのインストールなしでOracle Databaseに接続できます。OracleのNuGetページでも、Oracle.ManagedDataAccessは.NET Framework向けの100% managed codeのODP.NETとして説明されています。

一方、Oracle.DataAccessは管理対象外ドライバです。Oracle Clientに含まれるネイティブライブラリに依存するため、端末やサーバーにOracle Clientのインストールが必要になることがあります。また、32bit・64bitの不一致によるエラーが起きやすい点にも注意が必要です。

新規にC#でOracle接続を実装するなら、特別な理由がない限り、まずOracle.ManagedDataAccessまたはOracle.ManagedDataAccess.Coreを検討しましょう。

1-4. 初心者がつまずきやすい接続方式の選び方

初心者が最初につまずきやすいのは、「どのパッケージを入れればよいか」「Oracle Clientが必要なのか」「接続文字列に何を書けばよいか」という点です。

基本的な選び方は次のとおりです。

.NET FrameworkのWindowsアプリケーションや既存システムであれば、Oracle.ManagedDataAccessを使います。NuGet上では、現在のOracle.ManagedDataAccessパッケージは.NET Framework向けとして提供されています。

.NET 6、.NET 7、.NET 8など、いわゆる.NET Core系のアプリケーションであれば、Oracle.ManagedDataAccess.Coreを使います。Oracle公式ドキュメントでは、ODP.NET CoreはWindowsだけでなく非Windows環境でも利用でき、非WindowsではNuGetによる導入が案内されています。

既存の古いシステムでOracle.DataAccessを使っている場合は、Oracle Clientのバージョン、アプリケーションのビット数、参照アセンブリの場所を確認する必要があります。新規開発では、管理対象ドライバを使うことで環境依存のトラブルを減らせます。

2. C#でOracle接続に必要な開発環境

2-1. Visual Studioと.NETの準備

C#でOracleに接続するには、まずC#アプリケーションを開発できる環境を用意します。代表的にはVisual Studio、Visual Studio Code、またはJetBrains Riderなどを使います。

WindowsでGUIアプリケーションや業務用Windows Forms、WPFアプリを作る場合はVisual Studioが便利です。Web APIやバッチ処理、コンソールアプリであれば、Visual Studio Codeと.NET SDKでも開発できます。

.NETの種類によって使うODP.NETパッケージが変わるため、最初にプロジェクトのターゲットフレームワークを確認しておきましょう。

XML
<TargetFramework>net8.0</TargetFramework>

このようにnet6.0net7.0net8.0などになっている場合は、通常Oracle.ManagedDataAccess.Coreを使います。

一方、次のような.NET Frameworkプロジェクトの場合は、Oracle.ManagedDataAccessを使います。

XML
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>

2-2. Oracle Database側で確認すべき情報

C#側のコードを書く前に、Oracle Database側の接続情報を確認しておく必要があります。

最低限必要な情報は次の5つです。

ホスト名またはIPアドレス
ポート番号
サービス名またはSID
ユーザー名
パスワード

たとえば、次のような情報です。

ホスト名: dbserver.example.com
ポート番号: 1521
サービス名: ORCLPDB1
ユーザー名: app_user
パスワード: app_password

特に間違いやすいのが、サービス名とSIDの違いです。最近のOracle Databaseでは、接続文字列にSERVICE_NAMEを使うケースが多くなっています。PDB、つまりPluggable Databaseに接続する場合も、PDBのサービス名を使うのが一般的です。

2-3. NuGetでODP.NETを追加する方法

.NET 6以降のプロジェクトでは、次のコマンドでOracle.ManagedDataAccess.Coreを追加できます。

Bash
dotnet add package Oracle.ManagedDataAccess.Core

Visual Studioを使う場合は、ソリューションエクスプローラーでプロジェクトを右クリックし、「NuGetパッケージの管理」からOracle.ManagedDataAccess.Coreを検索してインストールします。

.NET Frameworkの場合は、次のパッケージを追加します。

Bash
Install-Package Oracle.ManagedDataAccess

または、Visual StudioのNuGetパッケージマネージャーからOracle.ManagedDataAccessを追加します。

Oracle公式ドキュメントでも、ODP.NETの管理対象ドライバやODP.NET CoreはNuGetを使って導入できることが説明されています。

2-4. Oracle Clientが必要なケースと不要なケース

Oracle.ManagedDataAccessOracle.ManagedDataAccess.Coreを使う場合、基本的にはOracle Clientを別途インストールしなくても接続できます。これが管理対象ドライバの大きなメリットです。

一方、次のようなケースではOracle Clientが関係してくることがあります。

既存システムがOracle.DataAccessを使っている
OCIベースの機能を利用している
古い.NET Frameworkアプリケーションを保守している
tnsnames.oraやsqlnet.oraを既存のOracle Client配下で管理している

新規開発で「C# Oracle 接続」を実装するなら、まずOracle Clientなしで構成できるOracle.ManagedDataAccess.CoreまたはOracle.ManagedDataAccessを選ぶと、配布や環境構築が簡単になります。

3. ODP.NETを使ったOracle接続の基本手順

3-1. Oracle.ManagedDataAccessをインストールする

.NET 6以降のコンソールアプリを例にすると、まずプロジェクトを作成します。

Bash
dotnet new console -n OracleSample
cd OracleSample
dotnet add package Oracle.ManagedDataAccess.Core

.NET FrameworkのWindowsアプリであれば、NuGetからOracle.ManagedDataAccessを追加します。

パッケージ追加後、C#ファイルでODP.NETのクラスを使えるようになります。

3-2. 必要なusingディレクティブを追加する

C#コードでは、次のusingを追加します。

C#
using Oracle.ManagedDataAccess.Client;

Oracle.ManagedDataAccess.Coreを使っている場合でも、名前空間は基本的に同じです。

たとえば、コンソールアプリでは次のような構成になります。

C#
using System;
using Oracle.ManagedDataAccess.Client;

Console.WriteLine("Oracle接続テストを開始します。");

3-3. OracleConnectionを使って接続する

Oracle Databaseに接続するには、OracleConnectionに接続文字列を渡してOpen()を呼び出します。

C#
using Oracle.ManagedDataAccess.Client;

var connectionString = "User Id=app_user;Password=app_password;Data Source=localhost:1521/ORCLPDB1";

using var connection = new OracleConnection(connectionString);
connection.Open();

Console.WriteLine("Oracle Databaseに接続しました。");

Data Sourceには、Oracle Databaseの接続先を指定します。EZCONNECT形式を使う場合は、次のように書けます。

ホスト名:ポート番号/サービス名

例は次のとおりです。

localhost:1521/ORCLPDB1
dbserver.example.com:1521/SALESDB

ODP.NETでは、Data Sourceに接続記述子全体を指定する方法や、Easy Connect構文を指定する方法も利用できます。

3-4. 接続確認用の最小サンプルコード

まずは、次のコードでOracleに接続できるか確認しましょう。

C#
using System;
using Oracle.ManagedDataAccess.Client;

class Program
{
static void Main()
{
var connectionString =
"User Id=app_user;Password=app_password;Data Source=localhost:1521/ORCLPDB1";

try
{
using var connection = new OracleConnection(connectionString);
connection.Open();

Console.WriteLine("接続成功");
Console.WriteLine($"Database Version: {connection.ServerVersion}");
}
catch (OracleException ex)
{
Console.WriteLine("Oracle接続エラーが発生しました。");
Console.WriteLine($"エラー番号: {ex.Number}");
Console.WriteLine($"メッセージ: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine("予期しないエラーが発生しました。");
Console.WriteLine(ex.Message);
}
}
}

このコードが成功すれば、C#からOracleへの基本接続はできています。失敗した場合は、接続文字列、ユーザー名、パスワード、リスナー、サービス名、ファイアウォールなどを順番に確認します。

4. C#で使うOracle接続文字列の書き方

4-1. ユーザー名・パスワード・接続先を指定する基本形

C#でOracle接続を行うときの基本的な接続文字列は次の形です。

C#
var connectionString =
"User Id=app_user;Password=app_password;Data Source=localhost:1521/ORCLPDB1";

主な要素は次のとおりです。

User Id: Oracleのユーザー名
Password: Oracleユーザーのパスワード
Data Source: 接続先データベース

Passwordは大文字・小文字を区別することがあります。ODP.NETでは、接続文字列中のパスワードは指定された大文字・小文字のまま認証に渡されます。

4-2. EZCONNECT形式で接続する方法

EZCONNECT形式は、tnsnames.oraを使わずに接続先を直接指定する方法です。

C#
var connectionString =
"User Id=scott;Password=tiger;Data Source=dbserver.example.com:1521/ORCLPDB1";

形式は次のようになります。

ホスト名:ポート番号/サービス名

ローカル環境のOracle Databaseに接続する場合は、次のようになります。

C#
var connectionString =
"User Id=hr;Password=hr_password;Data Source=localhost:1521/XEPDB1";

Oracle Database Express Editionを使っている場合、サービス名はXEPDB1XEになっていることがあります。実際のサービス名は、DB管理者に確認するか、SQL Developerなどで接続できている設定を確認しましょう。

4-3. tnsnames.oraを使って接続する方法

企業の開発環境では、tnsnames.oraに接続先を定義していることがあります。

tnsnames.oraの例です。

SALESDB =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = dbserver.example.com)(PORT = 1521))
(CONNECT_DATA =
(SERVICE_NAME = SALESDB)
)
)

この場合、C#の接続文字列ではData Sourceに別名を指定できます。

C#
var connectionString =
"User Id=app_user;Password=app_password;Data Source=SALESDB";

この方式では、アプリケーション側の接続文字列を短くできます。ただし、tnsnames.oraの場所やTNS_ADMIN環境変数の設定が正しくないと、ORA-12154が発生しやすくなります。

4-4. app.configやappsettings.jsonで接続文字列を管理する方法

接続文字列をC#コードに直接書くと、環境ごとの差し替えが難しくなります。実務では、設定ファイルから読み込む形にしましょう。

.NET Frameworkのapp.configでは、次のように書けます。

XML
<configuration>
<connectionStrings>
<add name="OracleDb"
connectionString="User Id=app_user;Password=app_password;Data Source=dbserver.example.com:1521/ORCLPDB1"
providerName="Oracle.ManagedDataAccess.Client" />
</connectionStrings>
</configuration>

C#側では次のように読み込みます。

C#
using System.Configuration;
using Oracle.ManagedDataAccess.Client;

var connectionString =
ConfigurationManager.ConnectionStrings["OracleDb"].ConnectionString;

using var connection = new OracleConnection(connectionString);
connection.Open();

.NET 6以降のappsettings.jsonでは、次のように管理できます。

JSON
{
"ConnectionStrings": {
"OracleDb": "User Id=app_user;Password=app_password;Data Source=dbserver.example.com:1521/ORCLPDB1"
}
}

ASP.NET Coreであれば、IConfigurationから取得できます。

C#
var connectionString =
configuration.GetConnectionString("OracleDb");

ODP.NETでは、.NET Configuration APIやtnsnames.orasqlnet.oraなどを使った構成も可能です。

4-5. 接続文字列にパスワードを直書きしないための注意点

サンプルコードでは説明のためにパスワードを直接書いていますが、本番環境では避けるべきです。ソースコードにパスワードを書くと、Gitなどのバージョン管理に残り、情報漏えいの原因になります。

本番では、次のような方法を検討します。

環境変数から読み込む
シークレット管理機能を使う
クラウドのSecret ManagerやKey Vaultを使う
CI/CDの変数として注入する
設定ファイルを暗号化またはアクセス制限する

たとえば、環境変数を使う場合は次のように書けます。

C#
var user = Environment.GetEnvironmentVariable("ORACLE_USER");
var password = Environment.GetEnvironmentVariable("ORACLE_PASSWORD");
var dataSource = Environment.GetEnvironmentVariable("ORACLE_DATA_SOURCE");

var connectionString =
$"User Id={user};Password={password};Data Source={dataSource}";

さらに安全性を高めたい場合は、OracleConnectionStringBuilderを使って接続文字列を組み立てる方法もあります。OracleConnectionStringBuilderは、ODP.NETで接続文字列を作成・変更するためのクラスとして提供されています。

C#
var builder = new OracleConnectionStringBuilder
{
UserID = user,
Password = password,
DataSource = dataSource
};

var connectionString = builder.ConnectionString;

5. OracleにSQLを実行する実践コード

5-1. SELECT文を実行してデータを取得する

C#からOracleにSELECT文を実行するには、OracleCommandOracleDataReaderを使います。

C#
using Oracle.ManagedDataAccess.Client;

var connectionString =
"User Id=app_user;Password=app_password;Data Source=localhost:1521/ORCLPDB1";

using var connection = new OracleConnection(connectionString);
connection.Open();

var sql = @"
SELECT EMPLOYEE_ID, EMPLOYEE_NAME, DEPARTMENT_ID
FROM EMPLOYEES
WHERE DEPARTMENT_ID = :departmentId
ORDER BY EMPLOYEE_ID";

using var command = new OracleCommand(sql, connection);
command.Parameters.Add(new OracleParameter("departmentId", 10));

using var reader = command.ExecuteReader();

while (reader.Read())
{
var employeeId = reader.GetInt32(reader.GetOrdinal("EMPLOYEE_ID"));
var employeeName = reader.GetString(reader.GetOrdinal("EMPLOYEE_NAME"));
var departmentId = reader.GetInt32(reader.GetOrdinal("DEPARTMENT_ID"));

Console.WriteLine($"{employeeId}: {employeeName} / 部署ID: {departmentId}");
}

Oracleのバインド変数は、一般的に:departmentIdのようにコロン付きで記述します。C#側ではOracleParameterを使って値を渡します。

5-2. INSERT・UPDATE・DELETEを実行する

INSERT、UPDATE、DELETEなどの更新系SQLでは、ExecuteNonQuery()を使います。

INSERTの例です。

C#
using Oracle.ManagedDataAccess.Client;

var sql = @"
INSERT INTO EMPLOYEES
(EMPLOYEE_ID, EMPLOYEE_NAME, DEPARTMENT_ID)
VALUES
(:employeeId, :employeeName, :departmentId)";

using var connection = new OracleConnection(connectionString);
connection.Open();

using var command = new OracleCommand(sql, connection);
command.Parameters.Add(new OracleParameter("employeeId", 1001));
command.Parameters.Add(new OracleParameter("employeeName", "Yamada Taro"));
command.Parameters.Add(new OracleParameter("departmentId", 10));

var affectedRows = command.ExecuteNonQuery();

Console.WriteLine($"{affectedRows}件追加しました。");

UPDATEの例です。

C#
var sql = @"
UPDATE EMPLOYEES
SET EMPLOYEE_NAME = :employeeName
WHERE EMPLOYEE_ID = :employeeId";

using var command = new OracleCommand(sql, connection);
command.Parameters.Add(new OracleParameter("employeeName", "Suzuki Ichiro"));
command.Parameters.Add(new OracleParameter("employeeId", 1001));

var affectedRows = command.ExecuteNonQuery();
Console.WriteLine($"{affectedRows}件更新しました。");

DELETEの例です。

C#
var sql = @"
DELETE FROM EMPLOYEES
WHERE EMPLOYEE_ID = :employeeId";

using var command = new OracleCommand(sql, connection);
command.Parameters.Add(new OracleParameter("employeeId", 1001));

var affectedRows = command.ExecuteNonQuery();
Console.WriteLine($"{affectedRows}件削除しました。");

5-3. OracleParameterでSQLインジェクションを防ぐ

ユーザー入力をSQL文字列に直接連結するのは危険です。

悪い例です。

C#
var sql = "SELECT * FROM EMPLOYEES WHERE EMPLOYEE_NAME = '" + inputName + "'";

このような書き方はSQLインジェクションの原因になります。必ずOracleParameterを使いましょう。

良い例です。

C#
var sql = @"
SELECT EMPLOYEE_ID, EMPLOYEE_NAME
FROM EMPLOYEES
WHERE EMPLOYEE_NAME = :employeeName";

using var command = new OracleCommand(sql, connection);
command.Parameters.Add(new OracleParameter("employeeName", inputName));

数値、日付、文字列のいずれであっても、外部から受け取った値はSQLに直接埋め込まず、パラメータとして渡すのが基本です。

日付条件の例です。

C#
var sql = @"
SELECT ORDER_ID, ORDER_DATE
FROM ORDERS
WHERE ORDER_DATE >= :fromDate";

using var command = new OracleCommand(sql, connection);
command.Parameters.Add(new OracleParameter("fromDate", new DateTime(2026, 1, 1)));

5-4. トランザクションを使って安全に更新する

複数の更新処理をまとめて成功または失敗させたい場合は、トランザクションを使います。

C#
using Oracle.ManagedDataAccess.Client;

using var connection = new OracleConnection(connectionString);
connection.Open();

using var transaction = connection.BeginTransaction();

try
{
var insertSql = @"
INSERT INTO ORDERS
(ORDER_ID, CUSTOMER_ID, ORDER_DATE)
VALUES
(:orderId, :customerId, :orderDate)";

using var insertCommand = new OracleCommand(insertSql, connection);
insertCommand.Transaction = transaction;
insertCommand.Parameters.Add(new OracleParameter("orderId", 5001));
insertCommand.Parameters.Add(new OracleParameter("customerId", 100));
insertCommand.Parameters.Add(new OracleParameter("orderDate", DateTime.Now));
insertCommand.ExecuteNonQuery();

var updateSql = @"
UPDATE CUSTOMERS
SET LAST_ORDER_DATE = :lastOrderDate
WHERE CUSTOMER_ID = :customerId";

using var updateCommand = new OracleCommand(updateSql, connection);
updateCommand.Transaction = transaction;
updateCommand.Parameters.Add(new OracleParameter("lastOrderDate", DateTime.Now));
updateCommand.Parameters.Add(new OracleParameter("customerId", 100));
updateCommand.ExecuteNonQuery();

transaction.Commit();
Console.WriteLine("トランザクションをコミットしました。");
}
catch
{
transaction.Rollback();
Console.WriteLine("エラーが発生したためロールバックしました。");
throw;
}

受注登録と在庫更新、請求データ作成など、複数テーブルを一貫して更新する処理ではトランザクションが必須です。

5-5. using文で接続・コマンド・リーダーを適切に解放する

C#でOracle接続を扱うときは、OracleConnectionOracleCommandOracleDataReaderを適切に解放する必要があります。using文を使うと、処理終了時に自動的にDispose()が呼ばれます。

C#
using var connection = new OracleConnection(connectionString);
connection.Open();

using var command = new OracleCommand(sql, connection);
using var reader = command.ExecuteReader();

while (reader.Read())
{
Console.WriteLine(reader["EMPLOYEE_NAME"]);
}

接続を開いたまま放置すると、接続数の枯渇やパフォーマンス低下につながります。ODP.NETでは接続プーリングが既定で有効ですが、Close()Dispose()を呼ばなければプールに戻らないため、usingで確実に解放しましょう。ODP.NETの接続プーリングはPooling接続文字列属性で制御でき、デフォルトで有効です。

6. C#からOracle接続できないときの主な原因

6-1. ORA-12154:接続識別子を解決できない

ORA-12154は、指定した接続識別子を解決できない場合に発生します。Oracle公式のエラーヘルプでも、接続識別子が構成済みのネーミング方法で接続記述子に解決できないことが原因として説明されています。

よくある原因は次のとおりです。

Data Sourceに指定した別名がtnsnames.oraに存在しない
tnsnames.oraの配置場所が間違っている
TNS_ADMIN環境変数が正しくない
接続先名のスペルミス
EZCONNECT形式の書き方が間違っている

たとえば、次のようにData Source=SALESDBと書いている場合、SALESDBtnsnames.oraで解決できなければORA-12154になります。

C#
var connectionString =
"User Id=app_user;Password=app_password;Data Source=SALESDB";

初心者の場合は、まずEZCONNECT形式に変えて接続できるか確認すると切り分けしやすいです。

C#
var connectionString =
"User Id=app_user;Password=app_password;Data Source=dbserver.example.com:1521/SALESDB";

6-2. ORA-12514:リスナーがサービスを認識できない

ORA-12514は、接続記述子で指定されたサービスをリスナーが認識できない場合に発生します。Oracle公式ドキュメントでも、リスナーが要求されたサービスを識別できないことを示すエラーとして説明されています。

よくある原因は次のとおりです。

サービス名が間違っている
SIDとサービス名を混同している
PDBのサービス名ではなくCDB名を指定している
データベースまたはPDBが起動していない
リスナーにサービスが登録されていない

たとえば、次の接続文字列でORCLが実際のサービス名でない場合、ORA-12514が発生します。

C#
var connectionString =
"User Id=app_user;Password=app_password;Data Source=dbserver.example.com:1521/ORCL";

対処としては、DBサーバー側でサービス名を確認し、正しいSERVICE_NAMEを使います。

6-3. ORA-01017:ユーザー名またはパスワードが無効

ORA-01017は、認証情報が不正な場合に発生します。Oracle公式のエラーヘルプでは、無効な資格情報が提供された、またはデータベースへのアクセス権限がない場合のエラーとして説明されています。

よくある原因は次のとおりです。

ユーザー名が間違っている
パスワードが間違っている
パスワードの大文字・小文字が違う
接続先DBが想定と違う
アカウントがロックされている
接続ユーザーに権限がない

Oracleではパスワードの大文字・小文字が問題になることがあります。特に古い環境から新しいOracle Databaseへ移行した場合、認証プロトコルやパスワードバージョンの影響でログインできないケースもあります。Oracle Database 12c Release 2以降では、デフォルトで大文字・小文字を区別しない古いパスワード認証の扱いが変わっています。

6-4. Could not load file or assemblyが発生する

Could not load file or assembly 'Oracle.ManagedDataAccess...'のようなエラーは、C#アプリケーションが必要なODP.NETアセンブリを読み込めない場合に発生します。

よくある原因は次のとおりです。

NuGetパッケージが正しく追加されていない
ビルド出力先にDLLがコピーされていない
.NET Frameworkとパッケージの対応が合っていない
古いバージョンの参照が残っている
app.configのbindingRedirectが不整合になっている

対処としては、まずNuGetパッケージを入れ直します。

Bash
dotnet remove package Oracle.ManagedDataAccess.Core
dotnet add package Oracle.ManagedDataAccess.Core

.NET Frameworkの場合は、参照設定とpackages.configまたはPackageReferenceを確認します。古いOracle.DataAccessへの参照が残っている場合は、不要な参照を削除しましょう。

6-5. 32bit・64bitの不一致で接続できない

Oracle.ManagedDataAccessを使っている場合、通常はOracle Clientの32bit・64bit問題を避けやすくなります。しかし、Oracle.DataAccessなどの管理対象外ドライバを使っている場合、アプリケーションのビット数とOracle Clientのビット数が一致していないと接続できません。

たとえば、次のような組み合わせは問題になります。

C#アプリケーション: 64bit
Oracle Client: 32bit

またはその逆です。

Visual Studioのプロジェクト設定で、プラットフォームターゲットがAny CPUx86x64のどれになっているか確認しましょう。既存システムでOracle.DataAccessを使う場合は、Oracle Clientのビット数に合わせる必要があります。

6-6. ファイアウォールやポート設定で接続できない

C#コードや接続文字列が正しくても、ネットワーク的にOracle Databaseへ到達できなければ接続できません。

確認すべき点は次のとおりです。

DBサーバーのホスト名を名前解決できるか
ポート1521などに接続できるか
ファイアウォールで遮断されていないか
VPN接続が必要ではないか
クラウドDBのセキュリティグループで許可されているか

Windowsであれば、PowerShellで次のように確認できます。

PowerShell
Test-NetConnection dbserver.example.com -Port 1521

ポート接続に失敗する場合、C#やODP.NETではなく、ネットワーク、ファイアウォール、リスナー、クラウド側のアクセス制御を確認する必要があります。

7. 接続エラーを切り分ける確認手順

7-1. Oracle DBにSQL Developerなどで接続できるか確認する

C#からOracleに接続できない場合、最初にSQL DeveloperやSQL*Plusなど別のツールで接続できるか確認しましょう。

SQL Developerで同じホスト名、ポート番号、サービス名、ユーザー名、パスワードを使って接続できるなら、データベース側やネットワーク側はおおむね正常です。その場合は、C#側の接続文字列やODP.NETの設定を重点的に確認します。

逆に、SQL Developerでも接続できない場合は、C#コード以前の問題です。サービス名、ユーザー、パスワード、リスナー、ネットワークを確認しましょう。

7-2. ホスト名・ポート番号・サービス名を確認する

接続情報は、1文字違うだけでも接続できません。特に次の間違いが多いです。

ホスト名の入力ミス
開発環境と本番環境の接続先取り違え
1521以外のポートを使っている
SIDをサービス名として書いている
PDBではなくCDBに接続しようとしている

EZCONNECT形式では、次の形になっているか確認します。

ホスト名:ポート番号/サービス名

例です。

dbserver.example.com:1521/ORCLPDB1

7-3. 接続文字列のData Sourceを見直す

Data Sourceの指定方法には複数あります。

EZCONNECT形式です。

C#
Data Source=dbserver.example.com:1521/ORCLPDB1

tnsnames.oraの別名を使う形式です。

C#
Data Source=SALESDB

接続記述子を直接書く形式です。

C#
Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=dbserver.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1)))

ORA-12154が出る場合は、まずtnsnames.oraの別名ではなくEZCONNECT形式で接続できるか試すと、問題の切り分けがしやすくなります。

7-4. tnsnames.oraやTNS_ADMINの設定を確認する

tnsnames.oraを使う場合、ODP.NETがそのファイルを見つけられる必要があります。

確認すべき点は次のとおりです。

tnsnames.oraが存在するか
接続別名が正しく定義されているか
括弧の対応が崩れていないか
TNS_ADMINが正しいディレクトリを指しているか
アプリケーション実行ユーザーから読み取れるか

TNS_ADMINは、tnsnames.orasqlnet.oraなどのネットワーク設定ファイルがあるディレクトリを指定するために使われます。ODP.NETの接続文字列ビルダーにも、TnsAdminプロパティが用意されています。

7-5. ODP.NETのバージョンと.NETの対応関係を確認する

.NET FrameworkなのにOracle.ManagedDataAccess.Coreを使おうとしていたり、.NET 6以降なのに古いOracle.ManagedDataAccessを参照していたりすると、ビルドや実行時に問題が起きます。

目安は次のとおりです。

.NET Framework: Oracle.ManagedDataAccess
.NET 6以降: Oracle.ManagedDataAccess.Core

NuGetのパッケージ情報では、Oracle.ManagedDataAccess.Coreは.NET Core系クライアントからOracle DatabaseにアクセスするためのODP.NET Coreパッケージとして説明されています。

パッケージ更新後にエラーが出る場合は、binobjフォルダを削除してクリーンビルドする、古い参照を削除する、複数プロジェクト間でパッケージバージョンを揃える、といった対応も有効です。

7-6. 例外メッセージから原因を特定する

C#では、OracleExceptionをcatchすると、Oracle固有のエラー番号を取得できます。

C#
try
{
using var connection = new OracleConnection(connectionString);
connection.Open();
}
catch (OracleException ex)
{
Console.WriteLine($"Oracle Error Number: {ex.Number}");
Console.WriteLine($"Message: {ex.Message}");
}

エラー番号によって、確認すべき場所が変わります。

12154: 接続識別子、tnsnames.ora、TNS_ADMIN
12514: サービス名、リスナー、DB起動状態
1017: ユーザー名、パスワード、アカウント状態

エラーメッセージを読まずに接続文字列だけを何度も変更すると、かえって原因がわかりにくくなります。まずエラー番号を確認し、原因の範囲を絞ることが大切です。

8. 実務で使いやすいOracle接続コードの設計

8-1. 接続処理を共通クラスに切り出す

実務では、各画面や各処理に毎回接続文字列を書いたり、OracleConnectionを直接生成したりすると保守性が悪くなります。接続処理は共通クラスに切り出しましょう。

C#
using Oracle.ManagedDataAccess.Client;

public class OracleConnectionFactory
{
private readonly string _connectionString;

public OracleConnectionFactory(string connectionString)
{
_connectionString = connectionString;
}

public OracleConnection CreateConnection()
{
return new OracleConnection(_connectionString);
}
}

使う側は次のようにします。

C#
var factory = new OracleConnectionFactory(connectionString);

using var connection = factory.CreateConnection();
connection.Open();

このようにしておけば、接続文字列の取得方法やログ出力、接続オプションを後から変更しやすくなります。

8-2. 設定ファイルから接続情報を読み込む

ASP.NET Coreや.NET 6以降のアプリでは、appsettings.jsonから接続文字列を読み込む設計が一般的です。

JSON
{
"ConnectionStrings": {
"OracleDb": "User Id=app_user;Password=app_password;Data Source=dbserver.example.com:1521/ORCLPDB1"
}
}

サービスクラスに接続ファクトリをDIする例です。

C#
public class EmployeeRepository
{
private readonly OracleConnectionFactory _connectionFactory;

public EmployeeRepository(OracleConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}

public List<string> GetEmployeeNames()
{
var result = new List<string>();

using var connection = _connectionFactory.CreateConnection();
connection.Open();

using var command = new OracleCommand(
"SELECT EMPLOYEE_NAME FROM EMPLOYEES ORDER BY EMPLOYEE_ID",
connection);

using var reader = command.ExecuteReader();

while (reader.Read())
{
result.Add(reader.GetString(0));
}

return result;
}
}

この設計にしておくと、テスト時には接続先を差し替えやすく、本番環境では環境変数やシークレット管理から接続文字列を注入しやすくなります。

8-3. 例外処理とログ出力を実装する

業務システムでは、接続エラーやSQLエラーを画面にそのまま表示するのは避けます。一方で、ログには原因調査に必要な情報を残す必要があります。

C#
try
{
using var connection = _connectionFactory.CreateConnection();
connection.Open();

using var command = new OracleCommand(sql, connection);
command.ExecuteNonQuery();
}
catch (OracleException ex)
{
logger.LogError(ex,
"Oracleエラーが発生しました。ErrorNumber={ErrorNumber}",
ex.Number);

throw new ApplicationException("データベース処理に失敗しました。", ex);
}

ログにパスワードや個人情報を出力しないように注意しましょう。接続文字列をそのままログ出力すると、Passwordが含まれる可能性があります。

8-4. コネクションプーリングを理解する

C#でOracleに接続するたびに物理接続を作成すると、パフォーマンスが低下します。ODP.NETでは接続プーリングがデフォルトで有効なため、OracleConnectionClose()またはDispose()すると、物理接続はすぐに破棄されるのではなくプールに戻されます。

接続プーリングを意識した基本は、次のとおりです。

接続は必要な直前でOpenする
使い終わったらすぐDisposeする
長時間OracleConnectionを保持し続けない
接続文字列を無駄に変えない

必要に応じて、接続文字列でプールサイズを指定できます。

C#
var connectionString =
"User Id=app_user;Password=app_password;Data Source=dbserver.example.com:1521/ORCLPDB1;" +
"Pooling=true;Min Pool Size=1;Max Pool Size=50;";

ただし、むやみにMax Pool Sizeを大きくすればよいわけではありません。Oracle Database側のセッション数、アプリケーションサーバーの台数、同時アクセス数を考慮して設定します。

8-5. 本番環境で避けるべき実装パターン

本番環境では、次のような実装は避けましょう。

接続文字列をソースコードに直書きする
SQLにユーザー入力を文字列連結する
OracleConnectionをstaticで使い回す
例外を握りつぶす
パスワードをログに出力する
トランザクションなしで複数更新を行う
接続をCloseせず放置する

特に、OracleConnectionをstatic変数としてアプリ全体で使い回す実装は危険です。接続切断、タイムアウト、マルチスレッド、トランザクション混在などの問題が起きやすくなります。

接続は毎回生成し、処理が終わったら破棄するのが基本です。接続プーリングが有効であれば、毎回new OracleConnection()しても、内部的にはプールが再利用されます。

9. C#とOracle接続でよくある質問

9-1. Oracle Clientなしで接続できるか

はい。Oracle.ManagedDataAccessまたはOracle.ManagedDataAccess.Coreを使えば、基本的にはOracle Clientなしで接続できます。

.NET Frameworkの場合はOracle.ManagedDataAccess、.NET 6以降の場合はOracle.ManagedDataAccess.Coreを使うのが一般的です。NuGetで導入できるため、配布先のPCやサーバーにOracle Clientをインストールしなくても構成しやすくなります。

ただし、既存システムがOracle.DataAccessを使っている場合や、Oracle Clientに依存した構成を使っている場合は、Oracle Clientが必要になることがあります。

9-2. .NET Frameworkと.NET 6以降で書き方は違うか

基本的なADO.NETの書き方は大きく変わりません。どちらもOracleConnectionOracleCommandOracleDataReaderを使います。

違いが出やすいのは、使用するNuGetパッケージと設定ファイルの扱いです。

.NET Framework: Oracle.ManagedDataAccess、app.config
.NET 6以降: Oracle.ManagedDataAccess.Core、appsettings.json

コード上の名前空間は基本的に次の形です。

C#
using Oracle.ManagedDataAccess.Client;

接続、SELECT、INSERT、UPDATE、DELETE、トランザクションの基本的な考え方は同じです。

9-3. Entity FrameworkやDapperでもOracleに接続できるか

はい、接続できます。

Dapperを使う場合は、OracleConnectionを作成してDapperの拡張メソッドを呼び出します。

C#
using Dapper;
using Oracle.ManagedDataAccess.Client;

using var connection = new OracleConnection(connectionString);

var employees = connection.Query<Employee>(
"SELECT EMPLOYEE_ID AS EmployeeId, EMPLOYEE_NAME AS EmployeeName FROM EMPLOYEES");

Entity Framework Coreを使う場合は、Oracle向けのEF Coreプロバイダを利用します。ただし、既存SQLを細かく制御したい業務システムでは、ODP.NETを直接使う方法やDapperを使う方法もよく選ばれます。

まずODP.NETでの基本接続を理解しておくと、DapperやEntity Frameworkを使う場合にもトラブルシューティングしやすくなります。

9-4. 接続文字列はどこに書くのが安全か

開発中はappsettings.Development.jsonやユーザーシークレット、環境変数に置くのが扱いやすいです。本番環境では、クラウドのシークレット管理サービス、環境変数、CI/CDの安全な変数管理などを使うのが望ましいです。

避けるべきなのは、次のような管理です。

Git管理されるソースコードにパスワードを書く
接続文字列をログに出す
共有フォルダに平文の設定ファイルを置く
本番DBの接続情報を開発者全員のローカルPCに配布する

最低限、接続文字列をコードから分離し、パスワードがリポジトリに残らないようにしましょう。

9-5. ODBCやOleDbではなくODP.NETを使うべきか

C#からOracleに接続するなら、通常はODP.NETを使うべきです。

ODBCやOleDbでも接続できる場合はありますが、Oracle固有の機能、パラメータ制御、パフォーマンス、トラブルシューティングのしやすさを考えると、Oracle公式の.NET向けプロバイダであるODP.NETを使う方が実務向きです。

特に新規開発では、次のどちらかを選ぶのが基本です。

.NET Framework: Oracle.ManagedDataAccess
.NET 6以降: Oracle.ManagedDataAccess.Core

ODBCやOleDbは、既存資産との互換性が必要な場合や、特殊な制約がある場合に検討する程度でよいでしょう。

まとめ

C#でOracleに接続するには、Oracle公式のODP.NETを使う方法が基本です。新規開発では、.NET FrameworkならOracle.ManagedDataAccess、.NET 6以降ならOracle.ManagedDataAccess.Coreを選ぶと、NuGetで導入でき、Oracle Clientなしでも構成しやすくなります。

接続の流れは、ODP.NETパッケージを追加し、Oracle.ManagedDataAccess.Clientをusingし、OracleConnectionに接続文字列を渡してOpen()するだけです。接続文字列では、User IdPasswordData Sourceを正しく指定します。Data Sourceには、EZCONNECT形式、tnsnames.oraの別名、接続記述子を使う方法があります。

SQLを実行する場合は、OracleCommandOracleParameterを使い、ユーザー入力を直接SQLに連結しないことが重要です。更新処理ではExecuteNonQuery()、検索処理ではExecuteReader()、複数更新ではOracleTransactionを使います。接続やコマンド、リーダーはusingで確実に解放しましょう。

接続できない場合は、エラー番号を見て原因を切り分けます。ORA-12154なら接続識別子やtnsnames.oraORA-12514ならサービス名やリスナー、ORA-01017ならユーザー名やパスワードを確認します。C#コードだけでなく、SQL Developerなど別ツールで接続できるかを確認すると、問題の範囲を絞りやすくなります。

実務では、接続処理を共通クラスに切り出し、接続文字列を設定ファイルや環境変数で管理し、例外処理とログ出力を適切に実装することが大切です。パスワードの直書き、SQL文字列連結、接続の使い回し、例外の握りつぶしは避けましょう。

C#とOracleの接続は、最初は接続文字列やODP.NETの種類で迷いやすいですが、基本構成を押さえれば安定して実装できます。まずはOracle.ManagedDataAccess.CoreまたはOracle.ManagedDataAccessを使った最小接続コードを動かし、そこからSELECT、更新処理、トランザクション、エラー対処へと段階的に広げていくのがおすすめです。