DataSet Group By с деревом выражений - PullRequest
0 голосов
/ 08 октября 2019

Я пытаюсь преобразовать следующее лямбда-выражение в дерево выражений

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 вместо анонимного типа с сопоставленными правильными свойствами

Но я не знаю, как сделать это, используя аномимный тип, любая помощь будет оценена.

Спасибо

...