Combine select clauses in linq to entities with anonymous types

.net anonymous-types c# expression-trees linq-to-entities

Question

How can i combine select clause in linq to entities in order to project into an anonymous type?
Assume that I have these entities:

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; }
}

Sometimes I only need to request few properties of my Person class:

Context.Persons.Where(...).Select(p => new 
{
    p.Name,
    PersonCity = p.Address.City,
    //other needed properties
});

And I also need to request the same properties of my Employee class plus the specific 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
});

Is it possible with expression-tree manipulations (or another solution) to combine two select clauses in order to not duplicate all the select clause from my Person entity?

Something like that:

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"
// }

Accepted Answer

No, there is no way to do exactly what you're asking for. The problem is that each anonymous type has to be created at compile time, but expression trees work at runtime.

I can see two ways to work around that:

  1. Your anonymous type for Employee would have a property called something like PersonData, which would contain the anonymous type with the information from Person.
  2. You would create normal types like PersonData and EmployeeData (which inherits from PersonData). Each type would be able to give you an expression to create it and EmployeeData's expression would be computed based on PersonData's expression.

In both cases you would need some expression trees plumbing, but it shouldn't be hard to do that.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why