Reputation: 21
I'm new to Automapper and am trying to map the data from an object in a list to an interface in a list. Add to that the lists are in different levels of the containing objects:
// class definitions
public class MyViewModel
{
public int ViewModelId { get; set; }
public IList<ViewItem> Page1Selections { get; set; }
public IList<ViewItem> Page2Selections { get; set; }
}
public class ViewItem
{
public int ItemId { get; set; }
public bool IsSelected { get; set; }
}
public class MyDbModel
{
public int DbModelId { get; set; }
public IPageSelection Page1Selections { get; set; }
public IPageSelection Page2Selections { get; set; }
}
public interface IPageSelection
{
int PageNumber { get; set; }
IList<IMyDbItem> PageSelections { get; set; }
}
public class PageSelection : IPageSelection
{
public int PageNumber { get; set; }
public IList<IMyDbItem> PageSelections { get; set; }
}
public interface IMyDbItem
{
int ItemId { get; set; }
bool IsSelected { get; set; }
}
public class MyDbItem : IMyDbItem
{
public int ItemId { get; set; }
public bool IsSelected { get; set; }
}
// mapping code
MyViewModel myVm = new MyViewModel();
myVm.ViewModelId = 123;
myVm.Page1Selections = new List<ViewItem>();
myVm.Page1Selections.Add(new ViewItem() { ItemId = 1, IsSelected = true });
myVm.Page2Selections = new List<ViewItem>();
myVm.Page2Selections.Add(new ViewItem() { ItemId = 2, IsSelected = true });
Mapper.Initialize(cfg =>
{
cfg.BindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
cfg.CreateMap<MyViewModel, MyDbModel>();
cfg.CreateMap<ViewItem, IMyDbItem>();
});
MyDbModel myDb = new MyDbModel();
myDb = Mapper.Map<MyDbModel>(myVm); //<== exception here
Sorry for the long attachment. But I'm fighting both an object to interface and hierarchical mismatch mapping problem.
Upvotes: 2
Views: 2209
Reputation: 126072
Here's one way you could accomplish this:
cfg.CreateMap<MyViewModel, MyDbModel>()
.ForMember(dest => dest.DbModelId, opt => opt.MapFrom(src => src.ViewModelId));
cfg.CreateMap<ViewItem, IMyDbItem>()
.ConstructUsing((ViewItem src) => new MyDbItem());
cfg.CreateMap<IList<ViewItem>, IPageSelection>()
.ConstructUsing((IList<ViewItem> src) => new PageSelection())
.ForMember(dest => dest.PageSelections, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.PageNumber, opt => opt.Ignore());
The error you were getting is because no mapping existed from IList<ViewItem>
to IPageSelection
. I've created that mapping above.
An important bit is the ConstructUsing
calls. I added those here because I assumed you wanted to use the concrete types that implement the interfaces you're mapping to. Otherwise, AutoMapper will create a proxy class that implements the destination interface.
The part that enables mapping to the IPageSelection.PageSelections
from IList<ViewItem>
is the opt.MapFrom(src => src)
part. This essentially tells AutoMapper to map from the list to the inner PageSelections
property, ultimately using the mapping from ViewItem
to IMyDbItem
.
Example: https://dotnetfiddle.net/DW9dfO
Upvotes: 1