一般化デリゲート内の大まかなクエリ、FuncまたはC#

c#-4.0 dapper generics

質問

私は結果としていくつかの異なるタイプで、このようなDapperクエリのいくつかの種類があります。これは、List <ClassA>を生成するこれらから特定のものです:

string anSql = GetSqlQueryText("query_name");
SqlConnection connection = GetSqlConnection();

List<ClassA> result = null;
try
{
    connection.Open();
    result = connection.Query<ClassA>(anSql, new    //want to move this part from here
    {
        param1 = "value1",
        param2 = "value2"
    }).ToList();                                    //to here out, to an outer call
}
catch //more error handling and retry logic omitted and this is a simplified version
{
    result = new List<ClassA>();       //this good to be filled up by the generic type
}
finally
{
    connection.Close();
}

私はこの種のクエリをGenDapperQuery <T>ジェネリックメソッドに参加させたいと思います。これはデリゲート(またはFunc / Actionなど)の助けを借りて呼び出すことができます(TはClassAまたはClassBなどとなります)。最終的なコード):

List<T> result = GenDapperQuery<T>(() =>
{
    result = connection.Query<T>(anSql, new
    {
        param1 = "value1",
        param2 = "value2"
    }).ToList();
}
//and I want to use the result then as a specific type e.g. ClassA
//either immediately or after a cast
result[0].Id = 3; //or
(result as List<ClassA>)[0].Id = 3;

だから私の目的は、接続、私のエラー処理/再試行のロジック、そしてもちろんDapperのクエリを複数回(私はそれらをクエリとタイプの数だけ書き留めたくないので)を使用することです。どういうふうに、このような(必要な)ジェネリックメソッドと、どのようなタイプの(ジェネリック)リストを作成して埋め込むのかを問合せるものです。

(この(希望の)ジェネリックメソッドは、一度接続を作成できるクラスと同じクラスになります)エラー処理部分は複雑になりますが、常にすべての型で同じです。そのため、複数回書き込む必要はありませんパラメータは入力と同じようにSQL文字列として自由に変更できます)。

私の問題は今、私自身のコードを取り囲む汎用のDapperクエリを書くことはできませんが、この(必要な)メソッドの外からの特定の注入関数を使用することができます。

これはC#で可能ですか?どんな提案も高く評価されます。

受け入れられた回答

これを達成する方法はたくさんあります。 1つのメカニズムは、Execute / ErrorHandlerのメソッドを作成することです。

public TResult ExecuteWrapper<TResult>(SqlConnection connection, Func<TResult, SqlConnection> func)
{
    TResult result;
    try
    {
        connection.Open();
        // Query will be wrapped in a function or lambda
        result = func(connection);
    }
    catch //more error handling and retry logic omitted and this is a simplified version
    {
        // Specifying a new TResult may be more difficult. You could either:
        // 1. Pass a default value in the method parameter
        //    result = defaultValue; // defaultValue is method parameter
        // 2. Use System.Activator to create a default instance
        //    result = (TResult)System.Activator(typeof(TResult));

        // Original: result = new List<ClassA>(); // this good to be filled up by the generic type
    }
    finally
    {
        connection.Close();
    }
    return result;
}

次に、あなたはこれを次のように使用します:

List<ClassA> result = ExecuteWrapper(connection, (cn) =>
    {
        string anSql = GetSqlQueryText("query_name");
        return cn.Query<ClassA>(anSql, new
            {
                param1 = "value1",
                param2 = "value2"
            }).ToList();        
    });

人気のある回答

ライアンの良い答えに基づいて私の改善を掲載しています。このラッパー関数は、SQL接続だけでなく、クエリーの名前も要求しています。だから、このソリューションは、呼び出し元側では1行、もう少しエレガントな方が短くなります。
変更されたラッパー関数:

public TResult ExecuteWrapper<TResult>(SqlConnection connection, string queryName, Func<SqlConnection, string, TResult> func)
{
   string anSql = GetSqlText(queryName);
   TResult result;
   try
   {
      connection.Open();
      result = func(connection, anSql);
   }
   catch
   {
      result = System.Activator.CreateInstance<TResult>(); //this is working in .NET 4.5 environment
   }
   finally
   {
      connection.Close();
   }
   return result;
}

そしてこれの呼び出し側:

List<ClassA> result = ExecuteWrapper(connection, "query_name", (conn, sql) =>
    {
        return conn.Query<ClassA>(sql, new
            {
                param1 = "value1",
                param2 = "value2"
            }).ToList();        
    });

彼の答えはライアンにもう一度感謝します。



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow