La manière la plus propre de mapper l'entité à DTO avec Linq Select?

J'ai essayé de venir avec un chiffon propre et réutilisable pour cartographier les entités de leur Otd. Voici un exemple de ce que je suis venu et où je suis bloqué.

Entités

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
    //Other properties not included in DTO
}

public class Address
{
    public int ID { get; set; }
    public string City { get; set; }
    //Other properties not included in DTO
}

Otd

public class PersonDTO
{
    public int ID { get; set; }
    public string Name { get; set; }
    public AddressDTO Address { get; set; }
}

public class AddressDTO
{
    public int ID { get; set; }
    public string City { get; set; }
}

Expressions

C'est ainsi que j'ai commencé à gérer la cartographie. Je voulais une solution qui ne serait pas l'exécution de la requête avant de la cartographie. J'ai été dit que si vous passez une Func<in, out> au lieu de Expression<Func<in, out>> qu'il va exécuter la requête avant de la cartographie.

public static Expressions
{
    public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
    {
        ID = person.ID,
        Name = person.Name,
        Address = new AddressDTO()
        {
            ID = person.Address.ID,
            City = person.Address.City
        }
    }
}

Un problème, c'est que j'ai déjà une expression qui associe un Address à un AddressDTO j'ai donc le code dupliqué. Cela permettra également de se briser si person.Address est null. Cela devient malpropre très rapide surtout si je veux afficher les autres entités liées à la personne dans cette même DTO. Il devient un nid des oiseaux de imbriqués les mappages.

J'ai essayé ce qui suit, mais Linq ne sais pas comment le gérer.

public static Expressions
{
    public static Expression<Func<Person, PersonDTO>> = (person) => new PersonDTO()
    {
        ID = person.ID,
        Name = person.Name,
        Address = Convert(person.Address)
    }

    public static AddressDTO Convert(Address source)
    {
        if (source == null) return null;
        return new AddressDTO()
        {
            ID = source.ID,
            City = source.City
        }
    }
}

Existe-il des solutions élégantes que je suis absent?

source d'informationauteur Jeff