在linq to entities中,如何将select子句与匿名类型结合使用?

3

我该如何在linq to entities中组合select语句以将结果投影成匿名类型?
假设我有以下实体:

public class Address
{
    public string City { get; set; }
    public int ZipCode { get; set; }
    //other properties
}

public class Person 
{
    public string Name { get; set; }
    public Address Address { get; set; }
    //a LOT of other properties
}

//extend person class with employee specific properties 
public class Employee : Person
{
    public double Salary { get; set; }
    public Person Manager { get; set; }
}

有时候我只需要请求我的Person类的几个属性:
Context.Persons.Where(...).Select(p => new 
{
    p.Name,
    PersonCity = p.Address.City,
    //other needed properties
});

我需要请求与我的雇员类相同的属性,再加上特定的属性:
Context.Employees.OfType<Employee>().Where(...).Select(e => new
{
    e.Salary,
    ManagerName = e.Manager.Name,
    e.Name,
    PersonCity = e.City.Name,
    //other needed properties identical as the previous select with Person entity
});

通过表达式树操作(或其他解决方案),是否可能将两个select子句合并,以避免从我的Person实体中重复所有select子句?

类似于这样:

var personSelect = p => new {
    p.Name,
    PersonCity = p.Address.City,
    //other needed properties
};

var employeeSelect = personSelect.Combine(e => new {
    e.Salary,
    ManagerName = e.Manager.Name
});

context.Employees.OfType<Employee>().Where(...).Select(employeeSelect).FirstOrDefault();
// returns an anonymous object 
// {
//     Name = "Joachim",
//     PersonCity = "Lyon",
//     <other Person properties>
//     Salary = 65432.10,
//     ManagerName = "Samuel"
// }

你是否基本上需要一个实现 Expression<Func<TInput2, TOutput2>> Combine<TInput1, TInput2, TOutput1, TOutput2> (Expression<Func<TInput1, TOutput1>> e1, Expression<Func<TInput2, TOutput2>) where TInput2 : TInput1 的方法? - Shlomo
哦等等,这不行。我明白svick的意思了。在employeeSelect中lambda创建的匿名类型不够全面,函数无法返回新的匿名类型。 - Shlomo
该函数必须具有签名 Expression<Func<TInput2, TOutput3>> Combine<TInput1, TInput2, TOutput1, TOutput2, TOutput3> (Expression<Func<TInput1, TOutput1>> e1, Expression<Func<TInput2, TOutput2>>) where TInput2 : TInput1,而且 TOutput3 在编译时不存在。 - Shlomo
好的,我明白了,谢谢@Sholmo和svick提供的帮助和解释。 - Joachim B
1个回答

3
不,无法完全按照您的要求执行。问题在于每个匿名类型必须在编译时创建,但表达式树在运行时工作。
我可以看到两种解决方法:
1. 您为“Employee”的匿名类型将具有一个名为“PersonData”的属性,其中包含来自“Person”的信息的匿名类型。 2. 您将创建像“PersonData”和“EmployeeData”这样的普通类型(它继承自“PersonData”)。每种类型都能够为您提供创建它的表达式,“EmployeeData”的表达式基于“PersonData”的表达式计算而来。
在这两种情况下,您都需要一些表达式树管道,但这不应该很难做到。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接