대리자, 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();
}

이런 종류의 쿼리를 DeleDate (또는 Func / Action 또는 다른 어떤 것)의 도움을 받아 호출 할 수있는 GenDapperQuery <T> 제네릭 메소드에 가입하려고합니다 (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 #에서 가능합니까? 어떤 제안이라도 높게 평가 될 것입니다.

수락 된 답변

이것을 성취 할 수있는 방법은 여러 가지가 있습니다. 하나의 메커니즘은 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 연결뿐만 아니라 쿼리의 이름도 요청합니다. 따라서이 솔루션은 호출자 측의 한 줄로 더 짧고 좀 더 우아 할 수도 있습니다.
수정 된 래퍼 함수 :

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();        
    });

Ryan에게 다시 한번 감사드립니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow