データベースでのSQL実行を楽にする

過去のブログのアーカイブ
この記事は前身のブログのアーカイブを引き継いだものです. 画像が正しく表示できないなど,コンテンツの表示に問題がある恐れがあります.

C#でデータベースのSQLを実行するのに必要な手続きは少々面倒。ということで簡単なライブラリを作って簡単に実行できるようなるライブラリを作ってみました。
仕組みはDbConnectionにSQL発行する拡張メソッドを追加する、そんだけです。
SQLインジェクション対策のためパラメータ指定もメソッドだけで簡単にできるように、脆弱性対策も楽ちんになるかもしれません

仕様

きっちりデータベースのインターフェースを実装しているデータベースライブラリならほとんど使えると思います。
DbConnectionに対応するDbCommandは毎回検索しています。そこの所でパフォーマンスを悪くしていますが、すべてのコネクションに対応させるため致し方ないことです。
逆に言えば、コネクションをMySQLやSQLiteとコロコロ変えてもSQLの実装や発行は同じままで大丈夫ということです。

ソースコード

SQLの発行

/// <summary>
/// パラメータを使用して新しいデータベースコマンドを発行します。
/// </summary>
/// <param name="db">使用するデータベース</param>
/// <param name="command">使用するSQL文。String.Formatのようなフォーマットで指定します。</param>
/// <param name="parameters">使用するパラメータ</param>
/// <returns>発行されたデータベースコマンドを返します。</returns>
public static System.Data.IDbCommand Create(
    this System.Data.IDbConnection db,
    string command,
    params object[] parameters)
{
    // コマンドを作成
    var com = db.CreateCommand();
    com.CommandText = command;
    com.CommandType = CommandType.Text;
    // パラメータを置き換える
    List<object> coms = new List<object>();
    for (int i = 0; i < parameters.Length; i++)
        coms.Add("@com" + i);
    com.CommandText = command = string.Format(command, coms.ToArray());
    // 対応するパラメータクラスを検索する
    Type paramType = null;
    Assembly asm = db.GetType().Assembly;
    foreach (Type t in asm.GetTypes())
    {
        //アセンブリ内のすべての型について、
        //プラグインとして有効か調べる
        if (t.IsClass && t.IsPublic && !t.IsAbstract &&
            t.GetInterface(typeof(IDbDataParameter).FullName) != null)
        { paramType = t; break; }
    }
    if (paramType == null)
        throw new Exception("This DBConnection is not support.");
    for (int i = 0; i < coms.Count; i++)
    {
        IDbDataParameter param = asm.CreateInstance(paramType.FullName) as IDbDataParameter;
        param.ParameterName = "@com" + i;
        param.Value = parameters[i];
        com.Parameters.Add(param);
    }
    return com;
}

名前空間を指定していない静的クラスを作り、そこの中にこのメソッドを入れてください。
データベースのコネクションからCreateメソッドでコマンドを発行。ExecuteNonQueryメソッド等で実行することができます。
コードを出来るだけ短縮化したいので更にSQLの実行も簡単にできるようなメソッドも作りました。

SQLの実行

public static void Execute(
    this System.Data.IDbCommand command)
{
    command.ExecuteNonQuery();
    command.Dispose();
}
public static void ExecuteReader(
    this System.Data.IDbCommand command,
    DbReadHandler handle)
{
    using (var reader = command.ExecuteReader())
    {
        if (handle != null)
            handle(reader);
        command.Dispose();
    }
}
public delegate void DbReadHandler(System.Data.IDataReader reader);

こちらの方は簡単な作りになっています。命令を実行したらすぐにコマンドクラスを破棄しています。再使用はできないようになっているので、何度も同じ命令を使う場合はこちらの拡張メソッドは使わないでください。
本来のExecuteReaderではなく、拡張メソッドの方を使うことでラムダ式で実行できるようになります。破棄も自動でするのでコードが一気に短く、楽になります。

サンプルソース

System.Data.Sqliteを使用したサンプルソースです。

SQLiteConnection con = new SQLiteConnection();
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\test.db";
con.ConnectionString = string.Format("Data source={0};", path);
con.Open();
con.Create("SELECT * FROM ExampleTable WHERE Name like '%太郎'")
    .ExecuteReader(
        (reader)=> {
            for (; reader.Read() ;){
                Console.WriteLine(reader["Name"].ToString());
            }
});

ソースコードはこちらでもダウンロードできます。
[wpdm_file id=1] 上記のソースコードに+αでおまけもいれてます。