【问题标题】:Dynamically select LINQ SELECT fields at runtime在运行时动态选择 LINQ SELECT 字段
【发布时间】:2019-06-19 20:36:57
【问题描述】:

我对具有多个链接表的数据库进行 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 本质上是指向 SQL 表的 EF 模型。 ClassA 与 ClassB 具有一对多的关系,因此,为什么我以这种方式查询它们。 ClassA 将是学生记录(姓名、地址、家庭等),ClassB 将是测试记录,其中学生可能有多个测试,每个测试都有参加日期、成绩、highest_score_of_class、lowest_score_of_class 等等。

我并不总是想要两个表的所有字段,因为可能有 100 万条记录,因此,为什么我更喜欢只选择特定查询和请求操作所需的内容。

【问题讨论】:

  • 听起来像是关注点分离的问题,如果没有那么多组合,只需使用if 声明
  • 每个类代表一个模型(SQL表),每个表大约30个字段,因此有多种组合。否则,是的,如果会很容易。

标签: c# .net linq frameworks entity


【解决方案1】:

这可能有点冗长,但表达式可以做到这一点,例如:

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()

【讨论】:

  • 太棒了。工作完美!先生你真棒。标记得很好,足以让我想象它是如何工作的。并感谢您的快速回复;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-01
  • 2011-06-29
  • 2013-07-02
  • 2016-04-18
  • 1970-01-01
  • 2012-02-16
  • 2019-12-30
相关资源
最近更新 更多