Combina le clausole select in linq con entità con tipi anonimi

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

Domanda

Come posso combinare la clausola select in linq con le entità per poter proiettare in un tipo anonimo?
Supponiamo che io abbia queste entità:

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

A volte ho solo bisogno di richiedere alcune proprietà della mia classe Person:

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

E ho anche bisogno di richiedere le stesse proprietà della mia classe Employee più le proprietà specifiche:

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

È possibile con manipolazioni di albero di espressioni ( o un'altra soluzione ) combinare due clausole di selezione per non duplicare tutta la clausola select dall'entità Person?

Qualcosa del genere:

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

Risposta accettata

No, non c'è modo di fare esattamente quello che stai chiedendo. Il problema è che ogni tipo anonimo deve essere creato in fase di compilazione, ma gli alberi di espressione funzionano in fase di runtime.

Posso vedere due modi per ovviare a questo:

  1. Il tuo tipo anonimo per Employee avrebbe una proprietà chiamata qualcosa come PersonData , che conterrebbe il tipo anonimo con le informazioni di Person .
  2. PersonData tipi normali come PersonData e EmployeeData (che ereditano da PersonData ). Ogni tipo sarebbe in grado di darti un'espressione per crearlo e l'espressione di EmployeeData verrebbe calcolata in base PersonData di PersonData .

In entrambi i casi è necessario disporre di alcuni alberi di espressione, ma non dovrebbe essere difficile farlo.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché