Firebird .Net Data Provider のラッパー

いままで以下のラッパークラスを公開してきたわけですが、

当然流れで Firebird .Net Data Provider 用のラッパークラスも欲しくなりますよね。「そっちかよっ!」という突っ込みはガン無視でw何気に作ってみました。もっともやってることはプレフィックスを置換してるだけなんで、ほとんど手間はかかってません。この辺り .NET データプロバイダの有難いところです。

実は私が本格的に RDBMS 使いだしたのは Interbase が初めてでした。その後 Interbaseオープンソース版である Firebird に移行したわけですが。当時は Delphi という強力な開発環境が存在し(・・・って今でもあるが(汗))、Delphi ともっとも親和性が高く高機能なRDMS が Firebird だったわけです。
Delphi は VB6 全盛期、マニアックなプログラマさん達にとっても人気があった開発ツールでしたが、Turbo Pascal の父と謳われた Anders Hejlsberg はじめ多くの優秀な人材が Microsoft に移ってしまい、さらに .NET Framework が誕生後、多くのユーザーが .NET に流れていってしまった感がありますねぇ。

ちなみに Delphi.NET が出た頃、何かぐだぐだした話があったみたいですが、その頃ちょうど VC にどっぷり嵌っていたので、詳しい話は判りませんが、その頃から急に衰退したように思えます。といっても Firebird Delphi の巻き添えをくらわず、MySQLPostgreSQL に続く第三のオープンソースデータベースとして、着実にシェアを増やしていったみたいですね。

#かなり推測交じってます。突っ込みたい方コメントどうぞ(汗


さて本題に戻ります。参照系の場合、こんな感じで使います。

string connectionString = 
    "data source=localhost;initial catalog=c:\\sample.fdb;user id=sysdba;password=masterkey";
using (FbWrapper wrapper = new FbWrapper(connectionString)) {
    FbCommand command = new FbCommand("SELECT * FROM Employees");
    DataTable dt = wrapper.GetDataTable(command);
    // ・・・・・・
}

更新系だとこうなる・・・そういえば Firebird の既定のユーザー名って sysdba だったんだ。書いてて思い出しました、懐かしいです。

string connectionString =
    "data source=localhost;initial catalog=c:\\sample.fdb;user id=sysdba;password=masterkey";
using (FbWrapper wrapper = new FbWrapper(connectionString)) {
    wrapper.Open();
    wrapper.BeginTransaction(IsolationLevel.Serializable);
    FbCommand command = new FbCommand
        (@"INSERT INTO Employees
                (Id, Name, Address, Telephone) 
           VALUES 
                (1, 'Hilapon', 'Tokyo-to', '030000000') ");
    wrapper.ExecNonQuery(command);
    wrapper.Commit();
}


以下ソースです。

class FbWrapper : IDisposable {

    /// <summary>コネクション</summary>
    FbConnection _connection;
    /// <summary>トランザクション</summary>
    FbTransaction _transaction;
    bool _disposed;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    /// <param name="connectString">接続文字列</param>
    public FbWrapper(string connectString) {
        _connection = new FbConnection(connectString);
    }

    /// <summary>
    /// リソースを解放します。
    /// </summary>
    /// <param name="disposing"></param>
    protected void Dispose(bool disposing) {

        if (_disposed == false) {
            if (disposing) {
                //
                if (_transaction != null) {
                    _transaction.Dispose();
                }

                if (_connection != null) {
                    this.Close();
                    _connection.Dispose();
                }
            }
            _disposed = true;
        }
    }

    /// <summary>
    /// リソースを解放します。
    /// </summary>
    public void Dispose() {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// トランザクションを開始します。
    /// </summary>
    public FbTransaction BeginTransaction() {

        try {
            _transaction = _connection.BeginTransaction(IsolationLevel.RepeatableRead);
        } catch (Exception) {
            throw;
        }
        return _transaction;
    }

    /// <summary>
    /// トランザクションを開始します。
    /// </summary>
    public FbTransaction BeginTransaction(IsolationLevel isolationLevel) {

        try {
            _transaction = _connection.BeginTransaction(isolationLevel);
        } catch (Exception) {
            throw;
        }
        return _transaction;
    }

    /// <summary>
    /// データベースへの接続を閉じます。
    /// </summary>
    public void Close() {
        try {
            if (_connection != null &&
                _connection.State == ConnectionState.Open) {
                _connection.Close();
            }
        } catch (Exception) {
            throw;
        }
    }

    /// <summary>
    /// トランザクション処理をコミットします。
    /// </summary>
    public void Commit() {
        try {
            if (_transaction != null) {
                _transaction.Commit();
            }
        } catch (Exception) {
            throw;
        }
    }

    /// <summary>
    /// 接続に対して SQL ステートメントを実行し、影響を受けた行数を返します。 
    /// </summary>
    /// <param name="command"><see cref="FbCommand">FbCommand</see> オブジェクト</param>
    /// <returns>影響を受けた行数</returns>
    public int ExecNonQuery(FbCommand command) {

        int ret = 0;
        try {
            command.Connection = _connection;
            if (_transaction != null) {
                command.Transaction = _transaction;
            }
            ret = command.ExecuteNonQuery();
        } catch (Exception) {
            throw;
        }
        return ret;
    }

    /// <summary>
    /// クエリを実行し、そのクエリが返す結果セットの最初の行にある最初の列を返します。
    /// </summary>
    /// <param name="command"><see cref="FbCommand">FbCommand</see> オブジェクト</param>
    /// <returns>結果セットの最初の行の最初の列</returns>
    public Object ExecScaler(FbCommand command) {

        Object ret = null;
        command.Connection = _connection;
        try {
            if (_transaction != null) {
                command.Transaction = _transaction;
            }
            ret = command.ExecuteScalar();
        } catch (Exception) {
            throw;
        }
        return ret;
    }

    /// <summary>
    /// データテーブル取得処理
    /// </summary>
    /// <param name="command"><see cref="FbCommand">FbCommand</see> オブジェクト</param>
    /// <returns><see cref="DataTable">DataTable</see>オブジェクト</returns>
    /// <remarks>
    /// パラメータに渡されたコマンドを実行し、データテーブルを取得します。
    /// </remarks>
    public DataTable GetDataTable(FbCommand command) {

        DataTable ret = null;
        try {
            command.Connection = _connection;
            if (_transaction != null) {
                command.Transaction = _transaction;
            }
            FbDataAdapter adapter = new FbDataAdapter(command);
            FbCommandBuilder builder = new FbCommandBuilder(adapter);
            ret = new DataTable();
            adapter.Fill(ret);

        } catch (Exception) {
            ret = null;
            throw;
        }
        return ret;
    }

    /// <summary>
    /// データベース接続を開きます。 
    /// </summary>
    public void Open() {
        try {
            _connection.Open();
        } catch (Exception) {
            throw;
        }
    }

    /// <summary>
    /// トランザクション処理をロールバックします。
    /// </summary>
    public void Rollback() {

        try {
            if (_transaction != null) {
                _transaction.Rollback();
            }
        } catch (Exception) {
            throw;
        }
    }

    /// <summary>
    /// データテーブル更新処理
    /// </summary>
    /// <param name="source">更新対象となるデータテーブル</param>
    /// <param name="command"><see cref="FbCommand">FbCommand</see> オブジェクト</param>
    /// <returns>更新に成功した行数</returns>
    public int Update(DataTable source, FbCommand command) {

        int ret = 0;
        try {
            command.Connection = _connection;
            if (_transaction != null) {
                command.Transaction = _transaction;
            }
            FbDataAdapter adapter = new FbDataAdapter(command);
            FbCommandBuilder builder = new FbCommandBuilder(adapter);
            ret = adapter.Update(source);

        } catch (Exception) {
            throw;
        }
        return ret;
    }
}

2010/10/10 追記

コードを少し修正しました。