LoginSignup
0
2

More than 5 years have passed since last update.

DbCommand 型の拡張 (SQL 実行)

Last updated at Posted at 2018-11-02

System.Data.Common.DbCommand 型のユーティリティ

拡張メソッド用に DbCommandExtensions クラスを用意

SQL 実行メソッドをラップ

DbCommand クラスには、SQL を実行するメソッドが 3 つあるが、実行したクエリをログ出力したい場合など、それぞれのメソッドをラップしておけば便利。

  • ExecuteNonQuery
  • ExecuteScalar
  • ExecuteReader

ログ出力

まずはログ出力用のメソッド(中身は適当に変更)

static void Log(this DbCommand command)
{
    Trace.WriteLine(command.CommandText);
}

ExecuteNonQuery

結果を伴わないクエリの実行

public static void Execute(this DbCommand command)
{
    if (command == null) throw new ArgumentNullException(nameof(command));
    try
    {
        command.Log();
        command.ExecuteNonQuery();
    }
    catch (Exception ex)
    {
        throw new ApplicationException("Attempt to ExecuteNonQuery failed.", ex);
    }
}

ExecuteScalar

結果を1つだけ取得するクエリの実行

public static TResult Execute<TResult>(this DbCommand command)
{
    Func<Type, bool> isNullable = type => type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>));
    Func<Type, Type> getBaseOrSelf = type => isNullable(type) ? Nullable.GetUnderlyingType(type) : type;

    if (command == null) throw new ArgumentNullException(nameof(command));
    try
    {
        command.Log();
        var result = command.ExecuteScalar();
        if (result == null) return default(TResult);
        if (result is DBNull) return default(TResult);
        return (TResult)Convert.ChangeType(result, getBaseOrSelf(typeof(TResult)));
    }
    catch (Exception ex)
    {
        throw new ApplicationException("Attempt to ExecuteScalar failed.", ex);
    }
}

ExecuteReader

テーブル情報を取得するクエリの実行
- IDataRecord から任意の型に変換するメソッドを渡す

public static IEnumerable<TResult> Execute<TResult>(this DbCommand command, Func<IDataRecord, TResult> parse)
{
    if (command == null) throw new ArgumentNullException(nameof(command));
    if (parse == null) throw new ArgumentNullException(nameof(parse));
    try
    {
        command.Log();
        return command.ExecuteYield(parse);
    }
    catch (Exception ex)
    {
        throw new ApplicationException("Attempt to ExecuteReader failed.", ex);
    }
}

private static IEnumerable<TResult> ExecuteYield<TResult>(this DbCommand command, Func<IDataRecord, TResult> parse)
{
    using (var reader = command.ExecuteReader())
    {
        while (reader.Read()) yield return parse(reader);
    }
}

使用例

using (var connection = new SqlConnection("接続文字列"))
{
    connection.Open();

    using (var command1 = connection.CreateCommand())
    {
        command1.CommandText = "UPDATE xxx SET value = 'test' WHERE key = 1";
        command1.Execute();
    }

    using (var command2 = connection.CreateCommand())
    {
        command2.CommandText = "SELECT value FROM xxx WHERE key = 1";
        var value = command2.Execute<string>();
    }

    using (var command3 = connection.CreateCommand())
    {
        command3.CommandText = "SELECT * FROM xxx";
        var records = command3.Execute(record =>
        {
            return new KeyValuPair<int, string>(record.GetInt32(0), record.GetString(1));
        });
    }
}
0
2
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
0
2