Frage

Let's say I have two items in EF model that could be projected to following DTOs:

public class AddressDto
{
    public int Id { get; set; }
    public string Address { get; set; }

    public static Expression<Func<Address, AddressDto>> Address2AddressDto()
    {
        return x => new AddressDto() {
            Id = x.Id,
            FullName = x.AddressLine
        };
    }
}

public class ClientDto
{
    public int Id { get; set; }
    public int FullName { get; set; }
    public AddressDto Address { get; set; }
}

How can I create a projection for ClientDto reusing projection from AddressDto to convert nested Address in Client? Basically I want something like:

public static Expression<Func<Client, ClientDto>> Client2ClientDto()
{
    return x => new ClientDto() {
        Id = x.Id,
        FullName = x.FullName,
        Address
           = <Apply projection AddressDto.Address2AddressDto to object x.Address>
    };
}

I'm aware that I can do:

public static Expression<Func<Client, ClientDto>> Client2ClientDto()
{
    return x => new ClientDto() {
        Id = x.Id,
        FullName = x.FullName,
        Address = new AddressDto() {
            Id = x.Id,
            FullName = x.AddressLine
        }
    };
}

But I would like to manage AddressDto projection in one place instead of every place this projection is used (real objects are far more complicated and code duplication will cause issues in long run).

In my caller code I want to do something like

dbRepo.Clients.Select(Client2ClientDto())

All my current attempts ended up with the exception:

The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.

War es hilfreich?

Lösung

Your best bet, if you want to follow this pattern, is probably to use LINQKit. It'll let you do this:

public static Expression<Func<Client, ClientDto>> Client2ClientDto()
{
    var addr = AddressDto.Address2AddressDto()
    return x => new ClientDto() {
        Id = x.Id,
        FullName = x.FullName,
        Address = addr.Invoke(x)
    };
}

But you'll have to call it like this:

dbRepo.Clients.AsExpandable().Select(Client2ClientDto())

Andere Tipps

Unless you already have all of your projections built, I would consider AutoMapper. You can create a static mapping very easily (it will by default map like properties, but you can add other mappings as well), and you can define the projection in your static mapping:

Mapper.CreateMap<Address, AddressDto>();
Mapper.CreateMap<Client, ClientDto>();

When AutpMapper goes to convert the Client object, it will see that there is a map for Address to AddressDto defined and will use that.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top