dapper querymultiple에 대한 런타임시 동적으로 유형 생성 Reflection을 사용한 읽기 메소드

dapper reflection types

문제

런타임에 동적으로 클래스 유형을 전달하려고합니다. 아래 코드는 코드 섹션에서 오류를 발생시킵니다.

    object newObject Activator.CreateInstance(Type.GetType(t.GetGenericArguments()[0].FullName));
    data.Read<newObject>();

나는 또한 시도했다.

    data.Read<Type.GetType(t.GetGenericArguments()[0].FullName)>();  

다음은 완벽한 방법입니다.

    public object FetchMultipleRecordSet(string storedProcedure, IList<QueryParameter> parameterCollection, object dataList)
    {
        if (!string.IsNullOrEmpty(storedProcedure))
        {
            using (SqlConnection sql = CreateDatabaseConnection())
            {
                DynamicParameters dynamicParameter = ConvertToDynamicParameters(parameterCollection);
                var data = sql.QueryMultiple(storedProcedure, dynamicParameter, null, null, commandType: CommandType.StoredProcedure);

                PropertyInfo[] properties = dataList.GetType().GetProperties();
                foreach (PropertyInfo property in properties)
                {
                    Type t = property.PropertyType;
                    if (t.BaseType == null && t.IsGenericType && t.Namespace == "System.Collection.Generic")
                    {
                        //property.SetValue(data.Read());
                        object newObject = Activator.CreateInstance(Type.GetType(t.GetGenericArguments()[0].FullName));
                        data.Read<>();    
                    }
                    else if (t.Namespace != "System")
                    {
                        //typeCollection.Add(Type.GetType(t.FullName));
                    }
                }
            }
        }

        return dataList;
    }

다음은 사용할보기 모델입니다.

    public class ResultCollection
    {
        public IList<ShortCodeList> ShortCodeListCollection { get; set; }
        public DateTime CurrentDate { get; set; }
        public UserMembershipPlan UserMembershipPlanRecord { get; set; }
        public IList<EmailRecipients> EmailRecipientsCollection { get; set; }
    }

형식을 data.Read ()에 전달하여 일반 형식의 속성이 결과 집합과 매핑되도록해야합니다. "newObject"또는 "Type.GetType (t.GetGenericArguments () [0]. 전체 이름)"을 전달하면 여전히 오류가 발생합니다. 서투른 것처럼 보일 수도 있지만 제대로 작동해야한다고 생각합니다.

전문가 답변

현재 dapper에 입력 된 API는 제네릭을 사용합니다. 형식이 지정되지 않은 API가 있지만 자체 멤버 매핑을 수행해야합니다. 유형을 통해 제네릭 메소드를 호출하려면 MakeGenericMethod 및 Invoke라는 일반 메소드에서 MethodInfo를 사용해야합니다. 다음과 같이 코드에 shim 메서드를 추가하여 dynamic 으로 스푸핑 할 수있는 방법이 있습니다.

dynamic template = ...  // activator etc
Evil(template, otherArgs...);

Evil<T>(T template, otherArgs...) {
    use some <T> method etc here
}

보다 완벽한 예로서 다음과 같은 작업이 있습니다.

public void TypeBasedViaDynamic()
{
    Type type = GetSomeType();

    dynamic template = Activator.CreateInstance(type);
    dynamic actual = CheetViaDynamic(template,
        "select @A as [A], @B as [B]", new { A = 123, B = "abc" });
    ((object)actual).GetType().IsEqualTo(type);
    int a = actual.A;
    string b = actual.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
}

T CheetViaDynamic<T>(T template, string query, object args)
{
    return connection.Query<T>(query, args).SingleOrDefault();
}
static Type GetSomeType()
{
    return typeof(SomeType);
}
public class SomeType
{
    public int A { get;set; }
    public string B { get;set; }
}

이것은 Type 에서부터 시작하여 더미 인스턴스 ( Activator 를 통해)와 dynamic 인스턴스를 통해 인스턴스를 채 웁니다. 예쁘지는 않지만 작동합니다. 그러나 Type 인스턴스를 매개 변수로 받아들이는 dapper에 몇 가지 변경 사항을 적용하여 이러한 해킹이 필요없는 다음 작업도 가능하게했습니다.

public void TypeBasedViaType()
{
    Type type = GetSomeType();

    dynamic actual = connection.Query(type,
        "select @A as [A], @B as [B]", new { A = 123, B = "abc" }
        ).FirstOrDefault();
    ((object)actual).GetType().IsEqualTo(type);
    int a = actual.A;
    string b = actual.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
}

멀티 그리드 리더기 :

public void TypeBasedViaTypeMulti()
{
    Type type = GetSomeType();

    dynamic first, second;
    using(var multi = connection.QueryMultiple(
        "select @A as [A], @B as [B]; select @C as [A], @D as [B]",
        new { A = 123, B = "abc", C = 456, D = "def" }))
    {
        first = multi.Read(type).Single();
        second = multi.Read(type).Single();
    }
    ((object)first).GetType().IsEqualTo(type);
    int a = first.A;
    string b = first.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");

    ((object)second).GetType().IsEqualTo(type);
    a = second.A;
    b = second.B;
    a.IsEqualTo(456);
    b.IsEqualTo("def");
}

이 새로운 API 예제에서 dynamic 것은 테스트 편의를위한 것입니다. dynamic 접근 방식은 중요하지 않습니다.



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