Динамический выбор полей LINQ SELECT во время выполнения - PullRequest
0 голосов
/ 26 января 2019

У меня есть запрос LINQ к базе данных с несколькими связанными таблицами, и мне нужно возвращать (SELECT) различные поля в зависимости от входных данных.

ClassA has ParamA, ParamB, and ICollection<ClassB>ClassBs
ClassB has ParamD, ParamE

Часть запроса Linq:

.Select(c => new ClassA()
    {
    ParamA = c.ParamA,
    ParamB = c.ParamB,
    ClassBs = c.ClassBs.Select(p => new ClassB()
        {
        ParamD = p.ParamD,
        ParamE = p.ParamE
        }).ToList()
    }).ToList();

На некоторых вызовах я буду хотеть только ParamA и ParamE.На другие вызовы, возможно, ParamB и ParamE.Я смог сделать эту работу с помощью выражений, но не для ICollection.Я попытался использовать Dynamic.Linq.Core, но не смог найти никаких примеров для обновления в SELECT.Я бы предпочел сделать это с MemberExpressions ...

[ОБНОВЛЕНИЕ] Немного больше контекста: ClassA и ClassB - это, по сути, модели EF, указывающие на таблицы SQL.ClassA имеет отношение один-ко-многим к ClassB, поэтому я и запрашиваю их таким образом.ClassA - это запись учащегося (имя, адрес, дом и т. Д.), ClassB - это запись теста, где у учащегося может быть более одного теста, у каждого теста есть дата, оценка, наивысший_счет_класса, наименьший_отчет_класса и многие другие.

Мне не всегда нужны все поля обеих таблиц, поскольку может быть 1 миллион записей, поэтому я предпочитаю ВЫБРАТЬ только то, что необходимо для конкретного запроса и запрашиваемой операции.

1 Ответ

0 голосов
/ 26 января 2019

Это может быть немного многословно, но выражения могут быть такими, например:

var typeClassA = typeof(ClassA);
var typeClassB = typeof(ClassB);

var parameterExpressionP = Expression.Parameter(typeClassB, "p");
var newExpression = Expression.New(typeClassB);

var paramDPropertyExpression = Expression.Property(parameterExpressionP, "ParamD");
var paramDMemberBinding = Expression.Bind(typeClassB.GetProperty("ParamD"), paramDPropertyExpression);

var paramEPropertyExpression = Expression.Property(parameterExpressionP, "ParamE");
var paramEMemberBinding = Expression.Bind(typeClassB.GetProperty("ParamE"), paramEPropertyExpression);

var memberInitExpression = Expression.MemberInit(
    newExpression,
    paramDMemberBinding, paramEMemberBinding);

var projectionExpression = Expression.Lambda<Func<ClassB, ClassB>>(memberInitExpression, parameterExpressionP);

var parameterExpressionC = Expression.Parameter(typeClassA, "c");
var selectParamExpression = Expression.Property(parameterExpressionC, "ClassBs");

var selectExpression = Expression.Call(
    typeof(Enumerable),
    nameof(Enumerable.Select),
    new[] { typeClassB, typeClassB },
    selectParamExpression, projectionExpression);

var toListExpression = Expression.Call(
    typeof(Enumerable),
    nameof(Enumerable.ToList),
    new[] { typeClassB },
    selectExpression);

Это создаст выражение что-то вроде:

c.ClassBs.Select(p => new ClassB() {ParamD = p.ParamD, ParamE = p.ParamE}).ToList()
...