Я пытаюсь преобразовать следующее лямбда-выражение в дерево выражений
var datatable = "<DataTable retrieved and filled with SQLCommand>"
var aggregate = datatable.AsEnumerable().GroupBy(x =>
new {
MeasureCode = x.Field<string>("CODMEASURE"),
FieldName = x.Field<string>("FIELDNAME"),
Formula = x.Field<string>("FORMULA"),
TableCode = x.Field<string>("CODTAB")})
.Select(x => new
{
Organization = String.Join(",",x.Select(z=>z.CODDIV)),
x.Key.MeasureCode,
x.Key.FieldName,
x.Key.Formula,
x.Key.TableCode
});
, и благодаря различным статьям я смог написать следующий код, который выполняет первую группу с помощью
.GroupBy(x =>
new {
MeasureCode = x.Field<string>("CODMEASURE"),
FieldName = x.Field<string>("FIELDNAME"),
Formula = x.Field<string>("FORMULA"),
TableCode = x.Field<string>("CODTAB")})
Ниже кода, который строит дерево выражений:
1. Объявите входной параметр «x»
var dataRowParameter = Expression.Parameter(typeof(DataRow), "x");
var dataRowType = typeof(DataRow);
2. Создайте анонимный тип с одним свойством для каждого столбца с данными с помощью класса TypeBuilder
Dictionary<string, Expression> GroupByFields = new Dictionary<string, Expression>();
var helper = new ReflectionHelper();
var myTypeBuilder = helper.GetTypeBuilder();
foreach (DataColumn column in table.Columns)
{
if (column.ColumnName.Equals("CODDIV")) continue;
// Add the column as dynamic object property
myTypeBuilder.DefineField(column.ColumnName, column.DataType, FieldAttributes.Public);
3. Зацикливаясь по столбцам, я также создаю выражение для доступа к методу поля DataRow, например x.Field ("columnName")
// Get the expression for dynamically call the DataRow field method
MethodInfo mi = typeof(DataRowExtensions).GetMethod("Field", new Type[] { typeof(DataRow), typeof(string) });
mi = mi.MakeGenericMethod(column.DataType);
var columnName = Expression.Constant(column.ColumnName, typeof(string));
var valueGetter = Expression.Call(mi, new Expression[] { dataRowParameter, columnName });
//Add method definition to the list of fields
GroupByFields.Add(column.ColumnName, valueGetter);
}
// Create the type and assign it to a "new" expression
var dynamicType = myTypeBuilder.CreateType();
4. Когда я получаю все столбцы, я создаю связь между свойством анонимного типа и DataRowField
var bindingArray = dynamicType.GetFields()
.Select(p => Expression.Bind(p, GroupByFields[p.Name]))
.OfType<MemberBinding>()
.ToArray();
var GroupedRow = Expression.New(dynamicType.GetConstructor(Type.EmptyTypes));
var memberInit = Expression.Convert(Expression.MemberInit(GroupedRow, bindingArray),typeof(object));
var predicate = Expression.Lambda<Func<DataRow, object>>(memberInit, dataRowParameter);
5. Затем, чтобы проверить результат, я делаю GroupBy, используя лямбду из моего дерева выражений и одну, записанную как обычное лямбда-выражение.
var groupByResult = table.AsEnumerable().AsQueryable().GroupBy(predicate);
var aggregate = table.AsEnumerable().AsQueryable().GroupBy(x =>
new
{
MeasureCode = x.Field<string>("CODMEASURE")
});
/*.Select(x => new
{
Organization = String.Join(",",x.Select(z=>z.Field<string>("CODDIV"))),
});*/
6. CorrectResult - это счет от группы с использованием лямбда-выражения LINQ, который дает правильный результат, вместо этого переменная результата возвращает неправильный результат, то есть просто все записи без группировки
var correctresult = aggregate.ToArray().Count();
var result = groupByResult.ToArray().Count();
return table;
IЯ пытался использовать представление отладки, чтобы понять разницу между двумя лямбда, но я вижу только небольшую разницу.
Тот, который возвращает правильный результат:
.Call System.Linq.Queryable.GroupBy(
.Constant<System.Linq.EnumerableQuery`1[System.Data.DataRow]>(System.Data.EnumerableRowCollection`1[System.Data.DataRow]),
'(.Lambda #Lambda1<System.Func`2[System.Data.DataRow,<>f__AnonymousType2`4[System.String]]>))
.Lambda #Lambda1<System.Func`2[System.Data.DataRow,<>f__AnonymousType2`4[System.String,System.String,System.String,System.String]]>(System.Data.DataRow $x)
{
.New <>f__AnonymousType2`4[System.String](
.Call System.Data.DataRowExtensions.Field(
$x,
"CODMEASURE"),
)
}
Тот, который НЕ ГРУППИРУЕТis
.Call System.Linq.Queryable.GroupBy(
.Constant<System.Linq.EnumerableQuery`1[System.Data.DataRow]>(System.Data.EnumerableRowCollection`1[System.Data.DataRow]),
'(.Lambda #Lambda1<System.Func`2[System.Data.DataRow,System.Object]>))
.Lambda #Lambda1<System.Func`2[System.Data.DataRow,System.Object]>(System.Data.DataRow $x) {
(System.Object).New 13d459a0-b85d-4c0d-8ab1-8f0e9af36ad7(){
CODMEASURE = .Call System.Data.DataRowExtensions.Field(
$x,
"CODMEASURE")
}
}
Итак, я предполагаю, что причина, по которой не происходит группировка, заключается в том, что объект, построенный с использованием дерева выражений, использует System.Object вместо анонимного типа с сопоставленными правильными свойствами
Но я не знаю, как сделать это, используя аномимный тип, любая помощь будет оценена.
Спасибо