ODP.NET＋C#でOracleに接続する

# はじめに
ポイントは以下の通り
　・OracleはDockerで用意
　・C#はローカルで用意

# 利用したdotnet コマンド
```powershell:dotnet.ps1
# .NET Coreのコンソールアプリケーション作成
> dotnet new console --framework net5.0
# .NET Framework 4.7.2のコンソールアプリケーション作成
> dotnet new console --target-framework-override net472

# プログラム実行
> dotnet run
# プログラム実行(Release実行)
> dotnet run --configuration Release

# プロジェクト ファイルにパッケージ参照追加
> dotnet add package System.Collections
> dotnet add package System.IO
> dotnet add package Oracle.ManagedDataAccess --version 12.2.1100
> dotnet add package System.Data
# プロジェクト ファイルのパッケージ参照削除
> dotnet remove package System.Linq

# ファイルの追加はコマンドなしでそのまま配置

# デバッグ出力で不要な表示をさせないようにしたい
# デバッグ コンソールで「!シンボル」と入力
```
◆dotnet コマンド
　https://docs.microsoft.com/ja-jp/dotnet/core/tools/dotnet

# Programming
```xml:App.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <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.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
    </DbProviderFactories>
  </system.data>
</configuration>
```
```csharp:ODPWrapper.cs
using Oracle.ManagedDataAccess.Client;
using System;
using System.Data;
using System.Data.Common;
 
public class ODPWrapper : IDisposable
{
    private DbProviderFactory _factory;
    private DbConnection _connection;
    private DbCommand _command;
    private DbTransaction _transaction;
 
    public ODPWrapper() : this("Data Source=localhost:9999/ORCLPDB1.localdomain;User ID=developer;Password=password"){}
 
    public ODPWrapper(string connectionString)
    {
        _factory = DbProviderFactories.GetFactory("Oracle.ManagedDataAccess.Client");
        DbConnect(connectionString);

        //_connection = new OracleConnection(connectionString);
        //ConnectionString = connectionString;
    }
 
    public DbConnection DbConnect(string connectionString)
    {
        _connection = _factory.CreateConnection();
        _connection.ConnectionString = connectionString;
        return _connection;
    }
 
    public void Open()
    {
        if ((_connection.State == ConnectionState.Closed))
        {
            _connection.Open();
        }
    }
 
    void Close()
    {
        if (_connection.State == ConnectionState.Open)
        {
            _connection.Close();
        }
    }
 
    public DbCommand CreateCommand()
    {
        DbCommand cmd = _factory.CreateCommand();
        cmd.Connection = _connection;
        cmd.GetType().GetProperty("BindByName").SetValue(cmd, true, null);
        return cmd;
    }
 
    public DbCommand CreateCommand(string sql)
    {
        DbCommand cmd = CreateCommand();
        cmd.CommandText = sql;
        return cmd;
    }
 
    /// <summary>
    /// DataTableを返す
    /// </summary>
    /// <param name="sql"></param>
    public DataTable GetDataTable(string sql)
    {
        if (_command == null)
        {
            _command = CreateCommand();
        }
        _command.CommandText = sql;
        DbDataAdapter da = _factory.CreateDataAdapter();
        da.SelectCommand = _command;
        DataTable dt = new DataTable();
        da.Fill(dt);
        return dt;
    }
 
    /// <summary>
    /// SQLを実行する
    /// </summary>
    /// <param name="sql"></param>
    public int ExecuteSql(string sql)
    {
        if (_command == null)
        {
            _command = CreateCommand();
        }
        _command.CommandText = sql;
        Open();
        int result = _command.ExecuteNonQuery();
        if (_transaction == null || _transaction.Connection == null)
        {
            Close();
        };
        return result;
    }
 
    public DbDataReader ExecuteReader(string sql)
    {
        if (_command == null)
        {
            _command = CreateCommand();
        }
        _command.CommandText = sql;
        Open();
        DbDataReader result = _command.ExecuteReader(CommandBehavior.CloseConnection);
        // Close();
        return result;
    }
 
    public void BeginTransaction()
    {
        Open();
        _transaction = _connection.BeginTransaction();
    }
 
    public void Commit()
    {
        _transaction.Commit();
        Close();
    }
 
    public void Rollback()
    {
        _transaction.Rollback();
        Close();
    }
 
    #region IDisposable Support
    
    private bool _disposed = false;
 
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // マネージ オブジェクト破棄
                if (_transaction != null)
                {
                    _transaction.Dispose();
                }
                if (_command != null)
                {
                    _command.Dispose();
                }
                if (_connection != null)
                {
                    if (_connection.State == ConnectionState.Open)
                    {
                        _connection.Close();
                    }
                    _command.Dispose();
                }
            }
 
            // マネージ オブジェクト破棄
 
            _disposed = true;
        }
    }
 
    ~ODPWrapper() {
      Dispose(false);
    }
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion IDisposable Support

}
```
```csharp:Program.cs
using Oracle.ManagedDataAccess.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;

namespace OracleOperation2
{
    class Program
    {
        static void Main(string[] args)
        {
            // 引数操作
            if(args.Length > 0)
            {
              Console.WriteLine(args.Length);              
            }

            string dataSource = "localhost:9999/ORCLPDB1.localdomain";
            string connectString = "user id=developer;password=password;data source=" + dataSource;
            try
            {
                using (ODPWrapper odpWrapper = new ODPWrapper())
                {
                    // Update
                    //odpWrapper.ExecuteSql("UPDATE emp SET sal=sal*1.1 WHERE empno=7369");
                    
                    // Assert
                    Console.WriteLine("GetDataTable実行!!");

                    // Select
                    DataTable dt = odpWrapper.GetDataTable("SELECT * FROM tab");
                    Console.WriteLine("GetDataTable終わり!!");

                    //データテーブルの結果を出力
                    for (int rowIndex = 0; rowIndex < dt.Rows.Count; rowIndex++)
                    {
                        for (int colIndex = 0; colIndex < dt.Columns.Count; colIndex++)
                        {
                            Console.Write(dt.Rows[rowIndex][colIndex].ToString());
                        }
                        Console.WriteLine();
                    }
                }

                // using (OracleConnection conn = new OracleConnection(connectString)) {
                //     try
                //     {
                //         conn.Open();
                //         System.Console.WriteLine("データベースに接続しました。");

                //         // データアクセス処理
                //         DbCommand cmd =  conn.CreateCommand();
                //         cmd.Connection = conn;
                //         cmd.CommandText = "SELECT * FROM tab";
                //         DbDataReader reader = cmd.ExecuteReader();
                //         while(reader.Read()){
                //             // 処理の実行
                //             System.Console.WriteLine(reader["TNAME"]);
                //         }
                //     }
                //     catch (Exception ex)
                //     {
                //         System.Console.WriteLine(ex.Message);
                //     }
                // }
            }
            catch (Exception ex)
            {
                System.Console.WriteLine("★エラー：" + ex.Message);
            }


            // 読み込みたいCSVファイルのパスを指定して開く
            StreamReader sr = new StreamReader(@".\Resources\migrationTargetTable.csv");
            {
                Dictionary<string, string> csvData = new Dictionary<string, string>();

                // 末尾まで繰り返す
                while (!sr.EndOfStream)
                {
                    // CSVファイルの一行を読み込む
                    string line = sr.ReadLine();
                    // 読み込んだ一行をカンマ毎に分けて配列に格納する
                    string[] values = line.Split(',');
 
                    // 配列からリストに格納する
                    List<string> lists = new List<string>();
                    lists.AddRange(values);
 
                    // コンソールに出力する
                    foreach (string list in lists)
                    {
                        System.Console.Write("{0} ", list);
                    }
                    System.Console.WriteLine();
                }
            }
        }
    }
}
```

# 参考サイト
【事前準備】
　◆.NET 5とVSCodeでデスクトップアプリ（ランチャー）
　　https://qiita.com/Kosen-amai/items/dffd8070d4357f31ae7c
　◆VSCodeでのGitの基本操作まとめ
　　https://qiita.com/y-tsutsu/items/2ba96b16b220fb5913be
　◆VSCodeで.NET Frameworkコンソールアプリをビルド＆デバッグする
　　https://qiita.com/hibara/items/fa66c3241293b7d43eae

---
　◆NuGet Gallery | Oracle.ManagedDataAccess 21.3.0
　　https://www.nuget.org/packages/oracle.manageddataaccess/
　◆【.NET】Oracleクライアント不要なODP.NET Managed Driverの接続方法
　　https://qiita.com/yaju/items/82df63b97a41720e197c
　◆C# Oracleに接続してselectするサンプル
　　https://itsakura.com/csharp-oracle
　◆ADO.NET　ORACLEでのSQL文内のパラメータの使い方
　　https://www.oborodukiyo.info/ADONET/VS2017/ADONET-ParametersOfORACLE
　◆空のプロジェクトからASP.NET MVC5 EntityFramework6 for Oracleを試す(SQL文を直接実行)
　　https://qiita.com/yaju/items/798e9cf738cd52d0c457
　◆ODP.NET ラッパー（Facade）クラスの作成
　　http://nkurilog.blogspot.com/2017/12/odpnet-facade.html
　◆Insert from C# into Oracle triggers doesn't execute
　　https://stackoverflow.com/questions/29195475/insert-from-c-sharp-into-oracle-triggers-doesnt-execute
　◆チュートリアル: Visual Studio Code を使用して .NET コンソール アプリケーションを作成する
　　https://docs.microsoft.com/ja-jp/dotnet/core/tutorials/with-visual-studio-code
　◆【C#】もう悩まない！CSV読み込みの最も簡単な方法を徹底解説
　　https://www.sejuku.net/blog/85579
　◆C#でCSVファイルを読み込んでコレクションに入れてみた
　　https://water2litter.net/rye/post/c_io_read_csv/
　◆VSCodeでC#開発をする方法
　　https://zenn.dev/midoliy/articles/9e3cff958ff89ba151de