람다 식에 GroupBy 동적 추가

expression-trees linq

문제

좋습니다, 나는 lambda 표현식과 LINQ 표현식 트리를 완전히 "얻지는 못한다"고 인정합니다. 내가하고있는 일 중 많은 부분이 잘라내어 붙여 넣기와 작동하는 것을 보는 것입니다. 많은 문서를 살펴 봤지만 아직 "아하"순간을 아직 못 찾았습니다.

그런 말로 ...

내 Linq 식에 GroupBy 식을 동적으로 추가하려고 시도하고 있습니다. 나는 여기에 질문을했다. Enumerable.GroupBy에 Linq.Expression을 만드는 데 도움이 필요 하다.

내가 본 것을 구현하려했습니다.

우선, 데이터베이스에 대한 엔티티 클래스가 있고 ObjCurLocViewNormalized라는 테이블이 있습니다.

초기 호출을하는 메소드가 있는데,

public IQueryable<ObjCurLocViewNormalized> getLocations()
{
    IQueryable<ObjCurLocViewNormalized> res = (from loc in tms.ObjCurLocViewNormalized
                               select loc);
    return res;
}

그래서 나는 부를 수있다 :

IQueryable<MetAmericanLinqDataModel.ObjCurLocViewNormalized> locations = american.getLocations();

지금까지 문제 없습니다.

이제 다음과 같이 임의의 열을 기준으로 그룹화하려고합니다.

var grouped = locations.addGroupBy(childLocationFieldName);

지금 당장 나는 방법이있다 :

static public System.Linq.IQueryable<System.Linq.IGrouping<string, TResult>> addGroupBy<TResult>(this IQueryable<TResult> query, string columnName)
{

    var providerType = query.Provider.GetType();
    // Find the specific type parameter (the T in IQueryable<T>)
    var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
    var tableType = iqueryableT.GetGenericArguments()[0];
    var tableName = tableType.Name;

    var data = Expression.Parameter(iqueryableT, "query");
    var arg = Expression.Parameter(tableType, tableName);
    var nameProperty = Expression.PropertyOrField(arg, columnName);
    var lambda = Expression.Lambda<Func<TResult, string>>(nameProperty, arg);

    var expression = Expression.Call(typeof(Enumerable), 
                                    "GroupBy", 
                                    new Type[] { tableType, typeof(string) },
                                    data, 
                                    lambda);
    var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg); // this is the line that produces the error I describe below
    var result = query.GroupBy(predicate).AsQueryable();
    return result;
}

이 모든 것은 괜찮습니다.하지만 실행할 때 오류가 발생합니다.

System.ArgumentException: Expression of type 'System.Collections.Generic.IEnumerable`1[System.Linq.IGrouping`2[System.String,MetAmericanLinqDataModel.ObjCurLocViewNormalized]]' cannot be used for return type 'System.String'

이 줄에서 오류가 발생합니다.

 var predicate = Expression.Lambda<Func<TResult, String>>(expression, arg);

동적으로 Where 절을 표현식에 추가 한 성공적인 작업에서이 코드를 복사하고 적용하고 있습니다. 그래서 나는 여기서 어둠 속에서 찌르다.

만약에 누군가가 이것에 대해 약간의 빛을 비추는 것을 도울 수 있다면 분명히 완전한 작업 코드를 게시하고 나를 위해 모든 생각을 다하는 것이 좋습니다 :) 그러나 이것이 단지 잘못된 이유를 설명하거나 내 머리를 감쌀 수 있다면 이러한 개념을 중심으로하면 좋을 것입니다. 람다 식의 기본과 실제 표현식을 만드는 것 사이의 차이를 줄이는데 도움이되는 문서를 가리킬 수 있다면 좋을 것입니다. 분명히 내 지식에는 큰 구멍이 있지만이 정보가 다른 사람들에게 유용 할 수 있다고 생각합니다.

시간 내 주셔서 감사합니다. 다른 곳에서 답을 찾으면 여기에 게시 해 드리겠습니다.

다시 한번 감사드립니다.

인기 답변

해결책은 매우 간단해야합니다.

public static IQueryable<IGrouping<TColumn, T>> DynamicGroupBy<T, TColumn>(
    IQueryable<T> source, string column)
{
    PropertyInfo columnProperty = typeof(T).GetProperty(column);
    var sourceParm = Expression.Parameter(typeof(T), "x");
    var propertyReference = Expression.Property(sourceParm, columnProperty);
    var groupBySelector = Expression.Lambda<Func<T, TColumn>>(propertyReference, sourceParm);

    return source.GroupBy(groupBySelector);
}

다음과 같은 샘플 클래스를 가정합니다.

public class TestClass
{
    public string TestProperty { get; set; }
}

다음과 같이 호출합니다.

var list = new List<TestClass>();
var queryable = list.AsQueryable();
DynamicGroupBy<TestClass, string>(queryable, "TestProperty");



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.