C#でODP.NETの自己流便利クラス（Bind変数利用）

# 概要
C#でODP.NETを使おうと思ったら大変だったので記事に残します。
自己流の自分用便利クラスなのでベストプラクティスは他にあると思います。
※環境はVisualStudio2019です

# 流れ
Oracle.ManagedDataAccsessのインストール
Oracleとの接続設定
Oracle操作用便利クラスの作成
便利クラスの使い方

# Oracle.ManagedDataAccsessのインストール
プロジェクトを右クリックし、「NuGet パッケージの管理(N)...」を選択
参照で「Oracle.ManagedDataAccsess」を検索し、インストール

# Oracleとの接続設定
いくつか方法があるようですが、今回はApp.Configを利用します。
Oracle.ManagedDataAccsessをインストールした時点で<oracle.manageddataaccess.client>が生成されています。
そこに必要な情報を入力してください。
○○○：エイリアス
△△△：DBサーバーのホスト名orIPアドレス

※ここに入力する内容は、tnsnames.oraに登録してある内容と同じです。
※dataSources内には複数のdataSourceを入れることができます。

```console
<oracle.manageddataaccess.client>
    <version number="*">
      <dataSources>
        <dataSource alias="○○○"
                descriptor="(DESCRIPTION = (ADDRESS = (PROTOCOL = tcp)(HOST = △△△)(PORT = 1521))(CONNECT_DATA = (SERVICE_NAME = orcl))) "/>
      </dataSources>
    </version>
</oracle.manageddataaccess.client>
```


# Oracle操作用便利クラスの作成
あくまで自己流なので、より良い方法があれば教えてください。
一応Transactionも考慮しています。（未検証）

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

namespace common {
    class DbControl {

        // DB接続
        private OracleConnection conn;

        // SQL発行に必要
        private OracleCommand cmd;

        // SELECT時の結果読み取りに利用
        private OracleDataReader reader;

        // Transactionに利用
        private OracleTransaction transaction;

        // Bind変数に利用する型
        public static int DATE = 0;
        public static int VARCHAR2 = 1;
        public static int DOUBLE = 2;
        public static int INT16 = 3;
        public static int INT32 = 4;

        /// <summary>
        /// コンストラクタ：iniファイルから取得した情報でDBと接続し、接続（OracleConnection）を保持する
        /// </summary>
        public DbControl() {
            string connectString = "user id = " + Main.OracleLogonName + "; password = " + Main.OraclePassWord + "; data source = " + Main.OracleDbName;

            try {
                conn = new OracleConnection(connectString);
                conn.Open();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
                conn.Close();
            }
        }

        /// <summary>
        /// SQL文を使用し、OracleCommandを作成する
        /// <para>string sql：assets/sqlから取得したSQL文の文字列</para>
        /// </summary>
        public void SetCommand(string sql) {
            cmd = new OracleCommand(sql, conn);
            // バインド変数の名前解決
            cmd.BindByName = true;
        }

        /// <summary>
        /// バインド変数の設定
        /// <para>string parameterName：カラム名</para>
        /// <para>object parameterValue：カラムの値。string、DateTime等を渡す</para>
        /// <para>int oracleDbType：カラムのデータタイプ指定。DbManagementの定数を渡す</para>
        /// </summary>
        public void SetBindVariable(string parameterName, object parameterValue, int oracleDbType) {
            OracleParameter dbParameter = cmd.CreateParameter();
            switch (oracleDbType) {
                case 0:
                    dbParameter.OracleDbType = OracleDbType.Date;
                    break;
                case 1:
                    dbParameter.OracleDbType = OracleDbType.Varchar2;
                    break;
                case 2:
                    dbParameter.OracleDbType = OracleDbType.Double;
                    break;
                case 3:
                    dbParameter.OracleDbType = OracleDbType.Int16;
                    break;
                case 4:
                    dbParameter.OracleDbType = OracleDbType.Int32;
                    break;
            }
            dbParameter.ParameterName = parameterName;
            dbParameter.Value = parameterValue;
            cmd.Parameters.Add(dbParameter);
        }

        /// <summary>
        /// Transaction：開始（成功すればCommitを呼び、失敗したらRollBackを呼ぶ必要がある）
        /// </summary>
        public void BeginTransaction() {
            transaction = conn.BeginTransaction();
        }

        /// <summary>
        /// Transaction：コミット
        /// </summary>
        public void Commit() {
            transaction.Commit();
        }

        /// <summary>
        /// Transaction：ロールバック
        /// </summary>
        public void RollBack() {
            transaction.Rollback();
        }

        /// <summary>
        /// SELECT系のSQLで使用
        /// <returns>return OracleDataReader：</returns>
        /// </summary>
        public OracleDataReader ExecuteReader() {
            try {
                reader = cmd.ExecuteReader();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
            return reader;
        }

        /// <summary>
        /// 実行系のSQLで使用
        /// <returns>return Boolean：</returns>
        /// </summary>
        public Boolean ExecuteNonQuery() {
            int res = 99;
            try {
                res = cmd.ExecuteNonQuery();
            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
            if (res >= 1) {
                return true;
            } else {
                return false;
            }
        }

        /// <summary>
        /// DBのコネクションを閉じる（readerがあればreaderも）
        /// </summary>
        public void Close() {
            // 実行系だとnullになる為
            if (reader != null) {
                reader.Close();
            }
            conn.Close();
        }

        // 
        public static String GetString(OracleDataReader read, string target) {
            if (read.GetValue(read.GetOrdinal(target)).ToString() == "") {
                return "";
            } else {
                return read.GetString(read.GetOrdinal(target));
            }
        }

        // 
        public static int GetInt16(OracleDataReader read, string target) {
            return read.GetInt16(read.GetOrdinal(target));
        }

        // 
        public static int GetInt32(OracleDataReader read, string target) {
            return read.GetInt32(read.GetOrdinal(target));
        }

        // 
        public static float GetFloat(OracleDataReader read, string target) {
            return read.GetFloat(read.GetOrdinal(target));
        }

        // 
        public static String GetDateString(OracleDataReader read, string target, string format) {
            if (read.GetValue(read.GetOrdinal(target)).ToString() == "") {
                return "";
            } else {
                return read.GetDateTime(read.GetOrdinal(target)).ToString(format);
            }
        }
    }
}

```

# 便利クラスの使い方
### SELECTしてみる
```C#
string sql = "SELECT name FROM Something WHERE hobby = :hobby;";

DbControl dbControlt = new DbControl();
dbControlt.SetCommand(sql);
// 第一引数はBind変数、第二引数は値、第三引数はカラムの型に合わせたもの
dbControlt.SetBindVariable("hobby", "山登り", DbControl.VARCHAR2);

OracleDataReader reader = dbControlt.ExecuteReader();
if (reader != null) {
  if (reader.HasRows) {
    while (reader.Read()) {
      Console.WriteLine(DbControl.GetString(reader, "name"));
    }
  }
}      

DbControl.Close();         
```
### UPDATEしてみる
```C#
string sql = "UPDATE Something SET hobby = :hobby WHERE name = :name;";

DbControl dbControlt = new DbControl();
dbControlt.SetCommand(sql);
dbControlt.SetBindVariable("hobby", "川登り", DbControl.VARCHAR2);
dbControlt.SetBindVariable("name", "田中", DbControl.VARCHAR2);

OracleDataReader reader = dbControlt.ExecuteReader();
if (dbManagement.ExecuteNonQuery()) {
  Console.WriteLine("成功");
}else{
  Console.WriteLine("失敗");
}

DbControl.Close();
```