Ответ 1
Во-первых, вы получите доступ к текущему сгруппированному значению как Key
в предложении Select:
.Select("new (Key as Group, Sum(Value) as TotalValue)");
Это должно заставить ваш запрос работать. Более сложный вопрос заключается в том, как повернуть возвращенные объекты, которые будут иметь динамически сгенерированный тип, который наследует от DynamicClass
, в статический тип.
Вариант 1: используйте отражение для доступа к свойствам динамического объекта Group
и TotalValue
.
Вариант 2: Используйте скомпилированные деревья выражений для генерации легкого кода для доступа к свойствам Group
и TotalValue
.
Вариант 3. Изменение динамической библиотеки для поддержки строго типизированного результата. Это оказывается довольно простым:
-
В
ExpressionParser.Parse()
запишите аргумент типа в частном поле:private Type newResultType; public Expression Parse(Type resultType) { newResultType = resultType; int exprPos = token.pos; // ...
-
В конце
ExpressionParser.ParseNew()
мы попытаемся использоватьnewResultType
перед тем, как поменять динамический тип:Expression ParseNew() { // ... NextToken(); Type type = newResultType ?? DynamicExpression.CreateClass(properties); MemberBinding[] bindings = new MemberBinding[properties.Count]; for (int i = 0; i < bindings.Length; i++) bindings[i] = Expression.Bind(type.GetProperty(properties[i].Name), expressions[i]); return Expression.MemberInit(Expression.New(type), bindings); }
-
Наконец, нам нужна строго типизированная версия
Select()
:public static IQueryable<TResult> Select<TResult>(this IQueryable source, string selector, params object[] values) { if (source == null) throw new ArgumentNullException("source"); if (selector == null) throw new ArgumentNullException("selector"); LambdaExpression lambda = DynamicExpression.ParseLambda(source.ElementType, typeof(TResult), selector, values); return source.Provider.CreateQuery<TResult>( Expression.Call( typeof(Queryable), "Select", new Type[] { source.ElementType, typeof(TResult) }, source.Expression, Expression.Quote(lambda))); }
Единственными изменениями от исходного
Select()
являются места, на которые мы ссылаемсяTResult
.
Теперь нам нужно вернуть именованный тип:
public class Result
{
public string Group { get; set; }
public double TotalValue { get; set; }
}
И ваш обновленный запрос будет выглядеть так:
IQueryable<Result> res = table1.AsQueryable()
.GroupBy(groupbyvalue, "it")
.Select<Result>("new (Key as Group, Sum(Value) as TotalValue)");