Using AutoMapper to unflatten a DTO

2019-01-06 13:46发布

I've been trying to use AutoMapper to save some time going from my DTOs to my domain objects, but I'm having trouble configuring the map so that it works, and I'm beginning to wonder if AutoMapper might be the wrong tool for the job.

Consider this example of domain objects (one entity and one value):

public class Person
{
    public string Name { get; set; }
    public StreetAddress Address { get; set; }
}

public class StreetAddress
{
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

My DTO (from a Linq-to-SQL object) is coming out looking roughly like this:

public class PersonDTO
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

I'd like to be able to do this in my repository:

return Mapper.Map<PersonDTO, Person>(result);

I've tried configuring AutoMapper every way I can figure, but I keep getting the generic Missing type map configuration or unsupported mapping error, with no details to tell me where I'm failing.

I've tried a number of different configurations, but here are a few:

Mapper.CreateMap<PersonDTO, Person>()
    .ForMember(dest => dest.Address, opt => opt.MapFrom(Mapper.Map<Person, Domain.StreetAddress>));

and

Mapper.CreateMap<Person, Domain.Person>()
    .ForMember(dest => dest.Address.Address1, opt => opt.MapFrom(src => src.Address))
    .ForMember(dest => dest.Address.City, opt => opt.MapFrom(src => src.City))
    .ForMember(dest => dest.Address.State, opt => opt.MapFrom(src => src.State));

I've read that flattening objects with AutoMapper is easy, but unflattening them isn't easy...or even possible. Can anyone tell me whether I'm trying to do the impossible, and if not what I'm doing wrong?

Note that my actual objects are a little more complicated, so it's possible I'm leaving out info that is the key to the error...if what I'm doing looks right I can provide more info or start simplifying my objects for testing.

7条回答
我命由我不由天
2楼-- · 2019-01-06 14:39

In addition to sydneyos answer and according to Trevor de Koekkoek comment, two way mapping is possible this way

public class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

public class PersonViewModel
{
    public string Name { get; set; }
    public string AddressStreet { get; set; }
    public string AddressCity { get; set; }
    public string AddressState { get; set; }
}

Automapper mappings

Mapper.Initialize(cfg => cfg.RecognizePrefixes("Address"));
Mapper.CreateMap<Person, PersonViewModel>();
Mapper.CreateMap<PersonViewModel, Address>();
Mapper.CreateMap<PersonViewModel, Person>()
    .ForMember(dest => dest.Address, opt => opt.MapFrom( src => src )));

If you implement NameOf class, you can get rid of prefix magic string

Mapper.Initialize(cfg => cfg.RecognizePrefixes(Nameof<Person>.Property(x => x.Address)));

EDIT: In C# 6

Mapper.Initialize(cfg => cfg.RecognizePrefixes(nameof(Person.Address)));
查看更多
登录 后发表回答