Reputation: 4001
I have a viewmodel that needs to display a certain IEnumerable
field as semicolon-separated textbox. At first I thought of using DefaultModelBinder
to transform it, but I had trouble thinking how to achieve it in both directions (dto <-> viewmodel).
Nicknames is the field I'm trying to display as one textbox separated by semicolon.
public class Parent
{
public IEnumerable<Child> Children { get; set; }
}
public class Child
{
public IEnumerable<string> Nicknames { get; set; }
}
So I decided to try AutoMapper, I created two ViewModels:
public class ParentViewModel
{
public IEnumerable<ChildViewModel> Children { get; set; }
}
public class ChildViewModel
{
public string Nicknames { get; set; }
}
Then, I created mappings, like this for the children (omitted the other-way conversion for brevity)
Mapper.CreateMap<Child, ChildViewModel>().ForMember(
d => d.Nicknames, o => o.ResolveUsing<ListToStringConverter>().FromMember(s => s.Nicknames);
Then, for the parent, created a naive map (again, omitted the other-way)
Mapper.CreateMap<Parent, ParentViewModel>();
I truly expected the child mappings occur automatically, but they don't, I've already created too much "proper" code to solve a really simple problem which in any other simpler/older non-MVC environment, I'd be done with a long time ago :) How can I proceed and tell AutoMapper to transform the children without writing another "children member resolver".
Have I overthought this and there's a simpler way?
Thank you!
Upvotes: 12
Views: 16991
Reputation: 4520
Found this solution https://stackoverflow.com/a/7555977/1586498, that works for me:
Mapper.CreateMap<ParentDto, Parent>()
.ForMember(m => m.Children, o => o.Ignore()) // To avoid automapping attempt
.AfterMap((p,o) => { o.Children = ToISet<ChildDto, Child>(p.Children); });
The ToISet
function is defined in the above link.
Simpler examples 'just work' in LinqPad - so more investigation is required.
A complete listing of a working program:
public class Child{ public string Name {get; set; }}
public class ChildDto{ public string NickName {get; set; }}
public class Parent{ public virtual IEnumerable<Child> Children {get; set; }}
public class ParentDto{ public IEnumerable<ChildDto> Kids {get; set; }}
private static void Main()
{
AutoMapper.Mapper.CreateMap<Parent, ParentDto>().ForMember(d=>d.Kids, opt=>opt.MapFrom(src=>src.Children));
AutoMapper.Mapper.CreateMap<Child, ChildDto>().ForMember(d=>d.NickName, opt=>opt.MapFrom(src=>src.Name));
var pList = new HashSet<Parent>{
new Parent{ Children = new HashSet<Child>{new Child{Name="1"}, new Child{Name="2"}}},
new Parent{ Children = new HashSet<Child>{new Child{Name="3"}, new Child{Name="4"}}},
};
var parentVm = AutoMapper.Mapper.Map<IEnumerable<Parent>, IEnumerable<ParentDto>>(pList);
parentVm.Dump();
}
Upvotes: 6
Reputation: 31033
try
Mapper.CreateMap<Parent, ParentViewModel>();
Mapper.CreateMap<Child, ChildViewModel>();
var v = Mapper.Map<Parent, ParentViewModel>(parent);
Upvotes: 14