Я запрограммировал следующий запрос, который выбирает столбцы сгруппированных ключей данных и суммирует столбец Сумма.Он отлично работает.
private static IEnumerable<GroupSum> GetListOfGroupedRows(IEnumerable<IGrouping<GroupKey, DataRow>> queryGroup)
{
IEnumerable<GroupSum> querySelect = queryGroup
.Select(g => new GroupSum
{
KeyS0 = g.Key.KeyS0,
KeyS1 = g.Key.KeyS1,
AggN0 = g.Sum(row => row.Field<double>("Amount"))
});
return querySelect;
}
В запросе используются следующие типы для группировки и суммирования.
private class GroupKey : IEquatable<GroupKey>
{
public string KeyS0 { get; set; }
public string KeyS1 { get; set; }
public bool Equals(GroupKey other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return string.Equals(this.KeyS0, other.KeyS0) &&
string.Equals(this.KeyS1, other.KeyS1);
}
public override int GetHashCode()
{
int hash0 = this.KeyS0 == null ? 0 : this.KeyS0.GetHashCode();
int hash1 = this.KeyS1 == null ? 0 : this.KeyS1.GetHashCode();
return hash0 + 31 * hash1;
}
}
private class GroupSum : GroupKey
{
public Double AggN0 { get; set; }
}
В качестве следующего шага я хочу запрограммировать эквивалентный запрос, используя выражения Linq.
Я столкнулся с проблемой, из-за которой я не знаю, как создать MethodCallExpression для:
g.Sum (row => row.Field ("Amount"))
Я запрограммировал приведенный ниже код.Я отметил в комментариях, где я застрял.
private static void GetListOfGroupedRowsExpress()
{
//The MethodInfo for generic Field<T>(DataRow, String) can be retrieved by:
MethodInfo methInfo = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(string) });
ParameterExpression expRow = Expression.Parameter(typeof(DataRow), "row"); //Parametr: (row =>....)
//Property to bind
PropertyInfo propertyInfo = typeof(GroupSum).GetProperty("AggN0");
//This returns properly: row.Field<double>("Amount")
MethodCallExpression expCall = GetFieldCallExpression(expRow, methInfo, propertyInfo.PropertyType, "Amount");
//This returns properly: row => row.Field<double>("Amount")
LambdaExpression expRowValues = Expression.Lambda<Func<DataRow, double>>(expCall, expRow);
NewExpression expNewGroupKey = Expression.New(typeof(GroupSum));
ParameterExpression expG = Expression.Parameter(typeof(GroupSum), "g");
//This returns properly method info for: double Sum<T>()
MethodInfo methodInfoSum = typeof(Queryable).GetMethods().First(m =>
m.Name == "Sum"
&& m.ReturnType == typeof(double)
&& m.IsGenericMethod
);
//This returns properly method info for: double Sum<DataRow>()
MethodInfo methodInfoSumDataRow = methodInfoSum.MakeGenericMethod(new Type[] { typeof(DataRow) });
//And here I'm stuck. The code below compiles but at runtime it throws an error:
//Expression of type 'TestLinq.TestLinqDataTable+GroupSum' cannot be used for parameter of type 'System.Linq.IQueryable`1[System.Data.DataRow]' of method 'Double Sum[DataRow](System.Linq.IQueryable`1[System.Data.DataRow], System.Linq.Expressions.Expression`1[System.Func`2[System.Data.DataRow,System.Double]])'
MethodCallExpression expSumRows = Expression.Call(
null,
methodInfoSumDataRow,
expG,
expRowValues);
}
private static MethodCallExpression GetFieldCallExpression(ParameterExpression expRow, MethodInfo methodFieldGeneric,
Type type, string columnName)
{
List<Expression> list = new List<Expression>();
list.Add(expRow);
ConstantExpression expColumnName = Expression.Constant(columnName, typeof(string));
list.Add(expColumnName);
MethodInfo methodFieldTyped = methodFieldGeneric.MakeGenericMethod(type);
MethodCallExpression expCall = Expression.Call(null, methodFieldTyped, list);
return expCall;
}
Может кто-нибудь помочь мне, пожалуйста, как построить выражение вызова для Sum ()?