【问题标题】:How do I reuse an Expression on a single object in another Expression如何在另一个表达式中的单个对象上重用表达式
【发布时间】:2015-09-25 14:13:44
【问题描述】:

我觉得我遗漏了一些简单的东西,但我还没有找到回答我问题的文档。

我最近一直在将一些 linq 投影分解为可重用的表达式。它在对集合进行操作时效果很好,但我似乎无法弄清楚如何将表达式应用于另一个表达式中的单个对象。下面是我想要完成的一个例子:

public class Person
{
    public string ID { get; set; }
    public string Name { get; set; }
}

public class PersonDto
{
    public string ID { get; set; }
    public string Name { get; set; }
}

public class Department
{
    Person Manager { get; set; }
    List<Person> Employees { get; set; }
}

public class DepartmentDto
{
    PersonDto Manager { get; set; }
    List<PersonDto> Employees { get; set; }
}

public Expression<Func<Person, PersonDto>> CreatePersonDto = p => new PersonDto
{
    ID = p.ID,
    Name = p.Name
};

public Expression<Func<Department, DepartmentDto>> CreateDepartmentDto = d => new DepartmentDto
{
    Manager = d.Manager // How do I transform this `Person` using `CreatePersonDto`
    Employees = d.Employees.Select(CreatePersonDto) //Does not work either
};

编辑:需要明确的是,我正在使用需要使用此表达式生成 SQL 语句的 Linq-to-Entities。因此,我无法将 Compile 表达式转换为 Func,因为我可能能够使用 Linq-to-Objects。

【问题讨论】:

  • CreatePersonDtoPerson 转换为PersonDto,但Manager 类型为Person,您将无法将PersonDto 分配给Person 变量(这就是你想要在Manager = // How do I.... 中做的事情
  • 我的示例中有一个错误。我已经修改了它。 DepartmentDto 应该由 PersonDto 和 List 组成。感谢您指出@codroipo
  • 第二行Employees = d.Employees.Select(CreatePersonDto) 是否有任何错误?它对我有用。 IIRC 不可能那么容易地在表达式中使用表达式。您必须使用 Expression 类上的静态方法手动创建表达式。
  • @Mayoor 你可能是对的。现在我已经仔细查看了我的实际源代码(而不是我匆忙创建的示例),我看到我将 CreatePersonDto 的等价物传递给了 DbSet 上的表达式之外的 Select。示例:dbSet.Select(CreatePersonDto)。它似乎在表达式的上下文中不起作用。
  • 我在使用Compile 时遇到的问题是,虽然它适用于 Linq to Objects,但不适用于 Linq to Entities。 Linq to Entities 需要评估最终转换为 SQL 查询的表达式。它无法将Func&lt;Person, PersonDto&gt; 评估为 sql

标签: c# entity-framework linq-to-entities linq-expressions


【解决方案1】:

您可以使用LINQKit 来扩展您在其他表达式中的表达式:

private static Expression<Func<Department, DepartmentDto>> CreateDepartmentDtoUnexpanded = d => new DepartmentDto
{
    Manager = CreatePersonDto.Invoke(d.Manager),
    Employees = d.Employees.Select(employee => CreatePersonDto.Invoke(employee))
        .ToList(),
};
public static Expression<Func<Department, DepartmentDto>> CreateDepartmentDto = CreateDepartmentDtoUnexpanded.Expand();

【讨论】:

  • 这个链接正是我要找的。我一直在努力阐明这个问题,这个页面解释得非常清楚。它也提供了一个解决方案!
【解决方案2】:

你可以:

public static Expression<Func<Department, DepartmentDto>> CreateDepartmentDto = d =>
     new DepartmentDto
        {
            Manager = CreatePersonDto.Compile()(d.Manager),
            Employees = d.Employees.Select(CreatePersonDto.Compile()).ToList() // Or declare Employees as IEnumerable and avoid ToList conversion
        };

显然,您可以存储编译后的Func,而不是调用两次Compile方法

【讨论】:

  • 这对 OP 不起作用(你可以在上面看到他的评论)。然而,他甚至没有发表任何评论来抱怨这一点(直到我在评论中问他)。这表明一种不尊重的态度,我一点也不喜欢。所以我刚刚删除了我的答案(这肯定有效)。您还应该删除此答案,无法编辑并将其保留在此处。他可能认为这里的每个人都是无知的,或者只是小白。我对 LinqToEntity 的了解已经足够了,所以我不必问他为什么它不起作用,这只是我眼睛的问题。
  • @Hopeless 我同意你关于删除 OP 的不尊重态度,但我认为如果有人因为遇到 OP 最初提出的问题而进入此页面,如果我不这样做,他可以找到答案不要删除帖子。
  • 如果你的回答有效,他会接受的。但是因为它不起作用,所以保留它对其他人没有任何好处。正确答案也相当简单,有人可以尝试挖掘一点以不费力气地找到正确答案(也许在一些团队的帮助下)。
  • @Hopeless @codroipo 你如何建议我继续这个问题?我同意你的观点,我处理得不好。我确实在 9/25 上添加了关于 Compile 问题的评论,我应该为每个答案添加类似的评论还是更新我的问题?坦率地说,我觉得这个问题存在根本性的缺陷。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 2020-03-23
  • 1970-01-01
  • 1970-01-01
  • 2013-03-13
  • 1970-01-01
相关资源
最近更新 更多