问题
In my data layer I have a repository that can return a list of items like this:
new List<Item> {
new Item { Title = "Something", DetailId = 500 },
new Item { Title = "Whatever", DetailId = 501 },
}
The repository has another method that can return details for these items when given the items detail ID:
// repository.GetDetail(500) would return something like:
new ItemDetail {
Id = 500,
Size = "Large"
}
Now, in my service layer I would like to map a the above list into something like this:
new List<ServiceItem> {
new ServiceItem { Title = "Something", Size = "Large" },
new ServiceItem { Title = "Whatever", Size = "Medium" },
}
Note that I need properties both from the objects in the list (Title
in this case) and from the detailed objects. Is there any good way to map this with AutoMapper?
I have thought about making a profile that depends on an instance of my repository, and then have AutoMapper do the detail requests, but it sort of feels messy to have AutoMapper fetch new data?
Is there a clean way to map from two objects into one?
回答1:
One possibility would be to wrap your Item and ItemDetail objects in a Tuple and define your Map based off that Tuple. The mapping code would look something like this.
Mapper.CreateMap<Tuple<Item, ItemDetail>, ServiceItem>()
.ForMember(d => d.Title, opt => opt.MapFrom(s => s.Item1.Title))
.ForMember(d => d.Size, opt => opt.MapFrom(s => s.Item2.Size));
You would have to join the correct Item and ItemDetail yourself. If you wanted Automapper to also match the Item to the correct ItemDetail, you would need to change the mapping so that during the resolution of Size, Automapper performs a lookup and returns the Size of the match. The code would look something like this.
Mapper.CreateMap<Item, ServiceItem>()
.ForMember(d => d.Size, opt => opt.MapFrom(s => itemDetails.Where(x => s.DetailId == x.Id).First().Size));
This map uses the automapping functionality of Automapper to map Item.Title to ServiceItem.Title. The map is using an IEnumerable named itemDetails to find the match, but it should be possible to replace it with a database call. Now since doing this type of lookup is something that I don't think Autmapper was designed to do, performance may not be that great for a large number of items. That would be something to test.
回答2:
This blog describes an approach to do this: http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx. It makes one Map() call per input object but at least wraps it up in a helper.
回答3:
Use ValueInjecter instead of AutoMapper, its easy to switch between the two, and ValueInjecter supports injecting values from multiple sources out of the box.
serviceItem.InjectFrom(item);
serviceItem.InjectFrom(itemDetail);
As a bonus, you don't have to do all the static mapping like you do with AutoMapper
来源:https://stackoverflow.com/questions/12051852/mapping-from-two-items-with-automapper