LoginSignup
39
50

More than 5 years have passed since last update.

【.NET】Oracleクライアント不要なODP.NET Managed Driverの接続方法

Last updated at Posted at 2018-09-22

はじめに

Oracle に接続する場合、対象PCに Oracle クライアントをインストールする必要があるアプリケーションがありまして、リプレース作業に伴い「ODP.NET Managed Driver」に切り替えてOracle クライアントのインストールする手順を省きたいと思っています。
「ODP.NET Managed Driver」は、.NET 4以降のアプリケーションから使用できます。

ちなみに Java の場合、「Oracle Thin JDBC Driver」を使えば Oracle クライアントを介せずに直接 Oracle に接続することができます。ようやっと Java と同じことが出来るわけですね。

環境

Windows 10 Home
Visual Studio 2017 Communicate
Oracle Database 11g Express Edition (Oracle Database XE)
Oracle.ManagedDataAccess Ver 4.122.18.3

記事を書く上で自宅PCの環境となります。

インストール

NuGetのソリューションのパッケージ管理で「ODP」で検索して、「Oracle.ManagedDataAccess」をインストールします。※2018/09/22現在のバージョンは、v18.3.0

参照に Oracle.ManagedDataAccess が追加されます。
また、App.config に自動的に設定が追加されます。

App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="oracle.manageddataaccess.client"
      type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.122.18.3, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
    </configSections>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
    </startup>
    <system.data>
        <DbProviderFactories>
            <remove invariant="Oracle.ManagedDataAccess.Client"/>
            <add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver"
                type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.122.18.3, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
        </DbProviderFactories>
    </system.data>
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <publisherPolicy apply="no"/>
                <assemblyIdentity name="Oracle.ManagedDataAccess" publicKeyToken="89b483f429c47342" culture="neutral"/>
                <bindingRedirect oldVersion="4.122.0.0 - 4.65535.65535.65535" newVersion="4.122.18.3"/>
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
    <oracle.manageddataaccess.client>
        <version number="*">
            <dataSources>
                <dataSource alias="SampleDataSource"
                    descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) "/>
            </dataSources>
        </version>
    </oracle.manageddataaccess.client>
</configuration>

接続方法

アプリから接続文字列で指定したデータソースの実体を解決するには、次のいずれかが必要になる。

  1. 接続文字列のDataSourceに直接指定
  2. app.configのdataSource要素にtnsnames.oraの内容をセット
  3. app.configのsetting要素にtnsnames.oraの置き場所をセット
  4. tnsnames.oraをexeファイルと同じフォルダに置く
  5. tnsnames.oraの内容を取得して接続文字列のDataSourceに指定

1.接続文字列のDataSourceに直接指定

一番シンプルに、接続文字列のDataSourceに「ホストIPアドレス/SID」をセットする。

接続方法1-1
string dataSource = "localhost/XE";
string connectString = "user id=scott;password=tiger;data source=" + dataSource;
using (OracleConnection conn = new OracleConnection(connectString)) {
    try {
        conn.Open();
        MessageBox.Show("データベースに接続しました。");
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

接続文字列のDataSourceに、Descriptorの内容をセットする。
注意として、Descriptorの内容についてすべてのキーワードがサポートされてはおらず、一般的に使用される一部のキーワードのみサポートとなっています。
ODP.NET Managed Driver(管理対象ドライバ)についての私的まとめ

接続方法1-2
string dataSource = "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)))";
string connectString = "user id=scott;password=tiger;data source=" + dataSource;
using (OracleConnection conn = new OracleConnection(connectString)) {
    try {
        conn.Open();
        MessageBox.Show("データベースに接続しました。");
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

2.app.configのdataSource要素にtnsnames.oraの内容をセット

app.configのdataSource要素にtnsnames.oraの内容を指定します。

App.config
<oracle.manageddataaccess.client>
    <version number="*">
        <dataSources>
            <dataSource alias="SampleDataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE))) "/>
        </dataSources>
    </version>
</oracle.manageddataaccess.client>

接続文字列のDataSourceにdataSourceのエイリアス名をセットします。

接続方法2
string dataSource = "SampleDataSource";
string connectString = "user id=scott;password=tiger;data source=" + dataSource;
using (OracleConnection conn = new OracleConnection(connectString)) {
    try {
        conn.Open();
        MessageBox.Show("データベースに接続しました。");
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

3.app.configのsetting要素にtnsnames.oraの置き場所をセット

app.configのsettings要素にtnsnames.oraの置き場所を指定します。
ORACLE_HOMEの場所は、コマンドプロンプト上で下記を実行すると表示されます。
※KEY_xe のところは、KEY_(SID名) となります。

>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_xe"

; 出力内容
HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_xe
    VERSION    REG_SZ    11.2
    ORACLE_HOME_NAME    REG_SZ    XE
    ORACLE_HOME    REG_SZ    C:\oraclexe\app\oracle\product\11.2.0\server

ちなみに環境変数に「%ORACLE_HOME%」をセットしたが、変なエラーになったので環境変数はやめました。WindowsはレジストリからORACLE_HOMEを取得しているので何か影響が出てしまうのかな。

App.config
<oracle.manageddataaccess.client>
    <version number="*">
        <settings>
            <setting name="TNS_ADMIN" value="C:\oraclexe\app\oracle\product\11.2.0\server\network\ADMIN" />
        </settings>
    </version>
</oracle.manageddataaccess.client>

tnsnames.ora ファイル

tnsname.ora
TEST =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XE)
    )
  )

接続文字列のDataSourceにネットサービス名(TNS名)を指定します。

接続方法3
string dataSource = "TEST";
string connectString = "user id=scott;password=tiger;data source=" + dataSource;
using (OracleConnection conn = new OracleConnection(connectString)) {
    try {
        conn.Open();
        MessageBox.Show("データベースに接続しました。");
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

4.tnsnames.oraをexeファイルと同じフォルダに置く

exeファイルの直下にtnsnames.oraファイルを置きます。

接続文字列のDataSourceにネットサービス名(TNS名)を指定します。

接続方法4
string dataSource = "TEST";
string connectString = "user id=scott;password=tiger;data source=" + dataSource;
using (OracleConnection conn = new OracleConnection(connectString)) {
    try {
        conn.Open();
        MessageBox.Show("データベースに接続しました。");
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

5.tnsnames.oraの内容を取得して接続文字列のDataSourceに指定

サーバー上で動かすツール用です。

WindowsではORACLE_HOMEの場所はレジストリに記述されています。レジストリからORACLE_HOMEの値を取得してtnsname.oraファイルの場所を見つけ、Descriptorの内容を接続文字列のDataSourceに指定します。

レジストリを取得する際には注意が必要です。AnyCPUにしていても「32ビットを優先」にチェックが付いていると、32ビットのレジストリを取得してしまうので、チェックを外す必要があります。
VisualStudioプロジェクトプロパティの「32ビットの優先」チェックボックス
32ビットを優先.png

private Dictionary<string, string> getDataSource()
{
    Dictionary<string, string> result = new Dictionary<string, string>();

    string baseKey = @"SOFTWARE\ORACLE";
    RegistryKey regkey = Registry.LocalMachine.OpenSubKey(baseKey, false);
    if (regkey == null) return result;

    string[] arySubKeyNames = regkey.GetSubKeyNames();

    regkey.Close();

    foreach (string subKeyName in arySubKeyNames)
    {
        if (subKeyName.IndexOf("KEY_") > -1)
        {
            RegistryKey subkey = Registry.LocalMachine.OpenSubKey(baseKey + "\\" + subKeyName, false);
            if (subkey == null) continue;

            string oraHome = (string)subkey.GetValue("ORACLE_HOME");
            subkey.Close();

            if (oraHome != null)
            {
                string path = oraHome + @"\network\admin\tnsnames.ora";
                StreamReader sr = new StreamReader(path);
                string tnsNames = sr.ReadToEnd();
                sr.Close();

                string[] lineAll = Regex.Split(tnsNames, @"^\s+[\r\n]|^[\r\n]", RegexOptions.Multiline);
                foreach (string line in lineAll)
                {
                    string str = line.Replace(Environment.NewLine, "").Trim();
                    if (!str.StartsWith("#") && str.IndexOf("=") > 0)
                    {
                        foreach (Match m in Regex.Matches(str, @"(^.*?)=.*?(\(.*\))"))
                        {
                            string section = m.Groups[1].Value.Trim().ToUpper();
                            result.Add(section, m.Groups[2].Value);
                        }
                    }
                }

                return result;
            }
        }
    }

    return result;
}

dic変数にはネットサービス名をキーにDescriptorの内容がセットされるので、dataSourceに指定します。

接続方法5
Dictionary<string, string> dic = getDataSource();
string dataSource = dic["TEST"];
string connectString = "user id=scott;password=tiger;data source=" + dataSource;
using (OracleConnection conn = new OracleConnection(connectString)) {
    try {
        conn.Open();
        MessageBox.Show("データベースに接続しました。");
    }
    catch (Exception ex) {
        MessageBox.Show(ex.Message);
    }
}

最後に

もう2018年9月です、Windows 10は.NET Framework 4.6が標準に搭載されています。
Windows 7の延長サポート終了日は2020年1月14日となります。

古い環境はリプレースしていきましょうよ。

39
50
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
39
50