У меня есть запрос 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 миллион записей, поэтому я предпочитаю выбирать только то, что необходимо для конкретного запроса и запрошенной операции.
Каждый класс представляет собой модель (таблицу SQL), около 30 полей на таблицу, поэтому существует множество комбинаций. В противном случае, да, если бы было достаточно легко.





Это может быть немного многословно, но выражения могут быть такими, например:
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()
Фантастика. Работал отлично! Вы, сэр, потрясающие. Хорошо помечено, достаточно для меня, чтобы визуализировать, как это работает. И Вам спасибо за быстрый ответ ;)
Похоже на проблему разделения проблем, просто используйте
ifЗаявление, если комбинаций не так много