Automapper not mapping all fields that are configured - c#

I have a db objects that i would like to map to my view object in my application, but not every property getting mapped.
here is my Automapper set up:
Here is my View class that i would like AutoMapper to map to
public class CustomerDetails
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Dob { get; set; }
public DateTime CreateDate { get; set; }
public decimal Balance { get; set; }
public List<Email> Emails { get; set; }
public List<Address> Addresses { get; set; }
public class Email
{
public Guid Id { get; set; }
public string EmailName { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
}
}
Here is db classes:
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual CustomerBalance Balance { get; set; }
public virtual ICollection<Email> Emails { get; set; }
public virtual ICollection<Address> Address { get; set; }
public class Email
{
public Guid Id { get; set; }
public string EmailName { get; set; }
public bool IsPrimary { get; set; }
public virtual Customer Customer { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
}
}
here is how i set up my configuration for AutoMapper
Mapper.Initialize(config =>
{
config.AddProfile<CustomerProfile>();
});
public class CustomerProfile : Profile
{
public CustomerProfile()
{
CreateMap<DataModels.Phone, Phone>();
CreateMap<DataModels.Email, Email>();
CreateMap<DataModels.Address, Address>();
CreateMap<DataModels.CustomerPin, Pin>()
.ForMember(x => x.PinNumber, y => y.MapFrom(s => s.Pin))
.ForMember(x => x.Id, y => y.MapFrom(s => s.Id))
;
CreateMap<Customer, CustomerDetails>()
.ForMember(x => x.Phones, y => y.MapFrom(s => s.Phones))
.ForMember(x => x.Emails, y => y.MapFrom(s => s.Emails))
.ForMember(x => x.Balance, y => y.MapFrom(s => s.Balance.Balance))
.ForMember(x => x.Pins, y => y.MapFrom(s => s.Pin))
.ForMember(x => x.Addresses, y => y.MapFrom(s => s.Address))
;
CreateMap<Customer, CustomerDetails>().ReverseMap();
}
}
The strange thing is is that everything getting mapped as expected, except the Addressesproperty and Balance on my CustomerDetails.cs. The list collection is null even though i specified to map it from a member. However, email List is getting mapped appropriately.
Am I missing something?

Related

Automapper Add Mapping to parent Object while converting child collection

There are some classes with relations for me
public class MasterList
{
public int ListId { get; set; }
public string ListName { get; set; }
public int CompanyId { get; set; }
public string Company { get; set; }
public int UniqueId { get; set; }
public DateTime Created { get; set; }
public List<MasterSubList> SubLists { get; set; }
}
public class MasterSubList
{
public int SubListId { get; set; }
public string SubListName { get; set; }
public string Status { get; set; }
public DateTime Created { get; set; }
public List<SubListClick> Clicks { get; set; }
}
public class SubListClick
{
public int ClickId { get; set; }
public string ClickName { get; set; }
}
Can we create a SubList ViewModel by copying all properties from associated MasterList for each of the MasterSubList using AutoMapper?
public class SubListViewModel
{
public int ListId { get; set; }
public string ListName { get; set; }
public int CompanyId { get; set; }
public string Company { get; set; }
public int UniqueId { get; set; }
public DateTime Created { get; set; }
public int SubListId { get; set; }
public string SubListName { get; set; }
public string Status { get; set; }
public DateTime Created { get; set; }
public List<SubListClick> Clicks { get; set; }
}
if my MasterList contain 2 items with 2 MasterSubList each , My resulting SubListViewModel should contain 4 items in total
Can we define automapper mapping against the SubListViewModel based on MasterSubList but include properties from parent MasterList
public class SubListViewModel: IMapFrom<MasterSubList>
{
public int ListId { get; set; }
public string ListName { get; set; }
public int CompanyId { get; set; }
public string Company { get; set; }
public int UniqueId { get; set; }
public DateTime ListCreated { get; set; }
public int SubListId { get; set; }
public string SubListName { get; set; }
public string Status { get; set; }
public DateTime Created { get; set; }
public List<SubListClick> Clicks { get; set; }
public void Mapping(Profile profile)
{
profile.CreateMap<EcastCampaign, ECastRecordsModel>()
.ForMember(d => d.ListId, opt => opt.MapFrom(p => p. ????????? )) how to access Parent object here
.ForMember(d => d.ListName, opt => opt.MapFrom(p => p.?????????))
.ForMember(d => d.CompanyId, opt => opt.MapFrom(p => p.?????????))
.ForMember(d => d.Company, opt => opt.MapFrom(p => p.?????????))
.ForMember(d => d.UniqueId, opt => opt.MapFrom(p => p.))
.ForMember(d => d.ListCreated, opt => opt.MapFrom(p => p.?????????))
}
}
or the mapping should be at some other way?
At present I am doing this conversion by looping through the list
List<SubListViewModel> eRecords = new List<SubListViewModel>();
foreach (MasterList list in apiData)
{
foreach (MasterSubList campign in list.SubLists)
{
SubListViewModel _record = new SubListViewModel();
_record.SubListId = campign.SubListId ;
_record.SubListName = campign.SubListName ;
_record.Status = campign.Status;
_record.CampaignCreated = campign.Created;
_record.Clicks= campign.Clicks;
// now populate parent properties
_record.ListId = list.ListId;
_record.ListName = list.ListName;
_record.CompanyId = list.CompanyId;
_record.Company = list.Company;
_record.UniqueId = list.UniqueId;
_record.ListCreated = list.Created;
eRecords.Add(_record);
}
}

How can use AutoMapper to map two collections of objects

I try to use AutoMapper but when I what to map 2 collection I get an error.
These are my entity and dto classes that I want to use AutoMapper:
public class HeadQuarters
{
public int Id { get; private set; }
public string HeadQuartersName { get; set; }
public string HeadQuartersCode { get; set; }
public string HeadQuartersDescription { get; set; }
public bool IsActiv { get; set; }
public ICollection<Adresa> Adresa { get; set; }
}
public class HeadQuartersDTO
{
public string HeadQuartersName { get; set; }
public string HeadQuartersCode { get; set; }
public string HeadQuartersDescription { get; set; }
public ICollection<AdresaDTO> Addresses { get; set; }
public EntityState Status { get; set; }
}
These are my entity and dto collection classes:
public class AdresaDTO
{
public int Id { get; set; }
public string Street { get; set; }
public string StreetNr { get; set; }
public string Block { get; set; }
public string Entrance{ get; set; }
public string Apartment{ get; set; }
public double? Longitude { get; set; }
public double? Latitude { get; set; }
public int? CityId { get; set; }
public EntityState Status { get; set; }
}
public partial class Adresa
{
public int Id { get; private set; }
public string Street { get; set; }
public string StreetNr { get; set; }
public string Block { get; set; }
public string Entrance{ get; set; }
public string Apartment{ get; set; }
public double? Longitude { get; set; }
public double? Latitude { get; set; }
public int CityId { get; set; }
public int? HeadQuartersId { get; set; }
public int? EmployeeId { get; set; }
public int? ContractPersonDataId { get; set; }
}
I write this code for to use AutoMapper:
public static HeadQuarters DtoToEntity(HeadQuartersDTO dto)
{
var mapper = new Mapper(MapperConfiguration());
return mapper.Map<HeadQuarters>(dto);
}
private static MapperConfiguration MapperConfiguration()
{
return new MapperConfiguration(cfg =>
cfg.CreateMap<HeadQuartersDTO, HeadQuarters>()
.ForMember(dest => dest.Adresa, act => act.MapFrom(src => src.Addresses)));
}
But when I add some in collection I get an error. This is the error message that I get:
If I understand what you’re trying to do, you should be able to update your code like this:
public static HeadQuarters DtoToEntity(HeadQuartersDTO dto)
{
var mapper = new Mapper(MapperConfiguration());
return mapper.Map<HeadQuarters>(dto);
}
private static MapperConfiguration MapperConfiguration()
{
return new MapperConfiguration(cfg =>
cfg.CreateMap<AdresaDTO, Adresa>()
.ForMember(dest => dest.CityId, act => act.MapFrom(src => src.CityId ?? default(int)))
.ForMember(dest => dest.HeadQuartersId, act => act.Ignore())
.ForMember(dest => dest.EmployeeId, act => act.Ignore())
.ForMember(dest => dest.ContractPersonDataId, act => act.Ignore());
cfg.CreateMap<HeadQuartersDTO, HeadQuarters>()
.ForMember(dest => dest.Id, act => act.Ignore())
.ForMember(dest => dest.IsActiv, act => act.Ignore())
.ForMember(dest => dest.Adresa, act => act.MapFrom(src => src.Addresses)));
}

AutoMapper map a collection Property value from its Parent property

I have two models, Receipt.cs and ReceiptProduct.cs. What I want to achieve is to map the ICollection ReceiptProducts fields like PurchaseOrderId and ReceiptId from its parent Receipt.
Receipt.cs
public class Receipt
{
public Guid Id { get; set; }
public string Reference { get; set; }
public string PurchaseOrderId { get; set; }
public virtual ICollection<ReceiptProduct> ReceiptProducts { get; set; }
}
ReceiptProduct.cs
public class ReceiptProduct
{
public Guid Id { get; set; }
public string ReceiptId { get; set; }
public string PurchaseOrderId { get; set; }
public string ProductName { get; set; }
public string ProductId { get; set; }
public string Note { get; set; }
}
ReceiptProducts.ReceiptId <= Receipt.Id
ReceiptProducts.PurchaseOrderId <= Receipt.PurchaseOrderId
I tried the below code. But I got the error
CreateMap<DataEntities.Receipt, BusinessEntities.Receipt>()
.ForMember(dest => dest.ReceiptProducts.Select(x=>x.ReceiptId), automapper => automapper.MapFrom(src => src.Id));
Error : AutoMapper.AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.
So how to map that collection property values.
try this.
public class ReceiptProduct
{
public Guid Id { get; set; }
public string ReceiptId { get; set; }
public string PurchaseOrderId { get; set; }
public string ProductName { get; set; }
public string ProductId { get; set; }
public string Note { get; set; }
**public Receipt Receipt { get; set; }**
}
Mapping
CreateMap<DataEntities.ReceiptProduct, BusinessEntities.Receipt>()
.ForMember(dest => x=>x.ReceiptId, opts => opts.MapFrom(src => src.Receipt.Id))
.ForMember(dest => x=>x.PurchaseOrderId , opts => opts.MapFrom(src => src.Receipt.PurchaseOrderId))
.ForMember(dest => x=>x.Reference , opts => opts.MapFrom(src => src.Receipt.Reference ));

automapper : map one object to many

I have the following domain model (one class):
public class DriverDomain
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int? TruckId { get; set; }
public int? TrailerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int? UnitNo { get; set; }
public int? GpsId { get; set; }
public string CompanyFEIN { get; set; }
public string CompanyName { get; set; }
public string CompanyAddress { get; set; }
public string CompanyCity { get; set; }
public string CompanyZIP { get; set; }
public string CompanyState { get; set; }
public System.DateTime? DOB { get; set; }
public string SSN { get; set; }
public string PhoneNo { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZIP { get; set; }
public string DLno { get; set; }
public string Dlstate { get; set; }
public System.DateTime? DLexp { get; set; }
public System.DateTime? MedExp { get; set; }
public System.DateTime? HireDate { get; set; }
public System.DateTime? TermDate { get; set; }
public bool Active { get; set; }
public bool DrugTest { get; set; }
public string Notes { get; set; }
public string CardNo { get; set; }
public string EmployeeNo { get; set; }
public bool? OwnerOp { get; set; }
public bool OccAcc { get; set; }
public decimal? WeeklyOccAcc { get; set; }
public bool Ifta { get; set; }
public decimal? WeeklyIfta { get; set; }
public bool TrailerRental { get; set; }
public decimal? WeeklyTrailerRent { get; set; }
public bool CargoIns { get; set; }
public decimal? WeeklyCargoIns { get; set; }
public decimal? PilotRebate { get; set; }
public bool OnlineAccess { get; set; }
public int? OnlineId { get; set; }
public bool ViewedSchedule { get; set; }
public int SchedulePriority { get; set; }
public bool Hourly { get; set; }
public decimal? HourlyPay { get; set; }
public string IpassTransponderId { get; set; }
public System.DateTime? RecordDate { get; set; }
public string RecordChangedBy { get; set; }
public string EmgcontactName { get; set; }
public string EmgcontactPhone { get; set; }
public string EmgcontactRelationship { get; set; }
public string Nickname { get; set; }
public string UserId { get; set; }
public string AspNetUserName { get; set; }
public string AvatarUrl { get; set; }
public bool PaidByPercent { get; set; }
public decimal? PercentPaid { get; set; }
public bool PaidByMile { get; set; }
public decimal? PayPerMile { get; set; }
public bool CompanyPlates { get; set; }
public decimal? WeeklyPlateCharge { get; set; }
public bool EnableEscrowDeductionOnPayroll { get; set; }
public decimal WeeklyEscrowDeduction { get; set; }
public bool ShowPersonalConveyance { get; set; } = false;
public bool ShowYardMoves { get; set; } = false;
public string StartTimeOfDay { get; set; } = "00:00:00.000";
}
and many view model classes, each of them can be mapped to this domain class:
public class DriverPersonalInfoVM
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public System.DateTime? DOB { get; set; }
public string SSN { get; set; }
public string PhoneNo { get; set; }
...
public class DriverEmploymentVM
{
public int Id { get; set; }
public System.DateTime? HireDate { get; set; }
public System.DateTime? TermDate { get; set; }
public bool DrugTest { get; set; }
public bool OnlineAccess { get; set; }
public bool ViewedSchedule { get; set; }
map rules:
CreateMap<Domain.POCO.Driver.DriverDomain, DriverPersonalInfoVM>();
CreateMap<Domain.POCO.Driver.DriverDomain, DriverEmploymentVM>();
CreateMap<Domain.POCO.Driver.DriverDomain, DriverPayrollVM>();
CreateMap<Domain.POCO.Driver.DriverDomain, DriverCompensationVM>();
CreateMap<Domain.POCO.Driver.DriverDomain, DriverFuelTollsVM>();
CreateMap<Domain.POCO.Driver.DriverDomain, DriverAvatarVM>();
it works fine.
But now I have the following view model class:
public class DriverEditVM
{
public DriverEditVM(int id)
{
Id = id;
PersonalInfo = new DriverPersonalInfoVM { Id = id };
Employment = new DriverEmploymentVM { Id = id };
Payroll = new DriverPayrollVM { Id = id };
Compensation = new DriverCompensationVM { Id = id };
FuelTolls = new DriverFuelTollsVM { Id = id };
Avatar = new DriverAvatarVM { Id = id };
}
public DriverPersonalInfoVM PersonalInfo { get; set; }
public DriverEmploymentVM Employment { get; set; }
public DriverPayrollVM Payroll { get; set; }
public DriverCompensationVM Compensation { get; set; }
public DriverFuelTollsVM FuelTolls { get; set; }
public DriverAvatarVM Avatar { get; set; }
}
and map rule:
CreateMap<Domain.POCO.Driver.DriverDomain, DriverEditVM>();
but when I try to map domain object to DriverEditVM:
var driver = _driverService.GetDriver(id.Value);
DriverEditVM model = mapper.Map<DriverEditVM>(driver);
I have empty properties PersonalInfo, Employment etc. How to map it?
As you have created maps for all your other view models that form part of your DriverEditVM, you should be able to do this:
CreateMap<Domain.POCO.Driver.DriverDomain, DriverEditVM>()
.ForAllMembers(opt => opt.MapFrom(src => src));
Edit
As some members are not being mapped, there are two approaches, explicitly ignore the un-mapped members or explicitly map the mapped members:
CreateMap<Domain.POCO.Driver.DriverDomain, DriverEditVM>()
.ForMember(dest => dest.IgnoredProperty1, opt => opt.Ignore())
.ForMember(dest => dest.IgnoredProperty2, opt => opt.Ignore())
.ForAllOtherMembers(opt => opt.MapFrom(src => src));
Or
CreateMap<Domain.POCO.Driver.DriverDomain, DriverEditVM>()
.ForMember(dest => dest.PersonalInfo, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.Employment, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.Payroll, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.Compensation, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.FuelTolls, opt => opt.MapFrom(src => src))
.ForMember(dest => dest.Avatar, opt => opt.MapFrom(src => src))
.ForAllOtherMembers(opt => opt.Ignore());
Solved this problem :
CreateMap<Domain.POCO.Driver.DriverDomain, DriverEditVM>()
.ForMember(p => p.PersonalInfo, p => p.MapFrom(src => src))
.ForMember(p => p.Avatar, p => p.MapFrom(src => src))
.ForMember(p => p.Compensation, p => p.MapFrom(src => src))
.ForMember(p => p.Employment, p => p.MapFrom(src => src))
.ForMember(p => p.FuelTolls, p => p.MapFrom(src => src))
.ForMember(p => p.Payroll, p => p.MapFrom(src => src))
;

AutoMapper - How to Map to three level deep

I'm trying to user AutoMapper to flatten a Entity with relation to another Entity which has relation to third Entity to view model
How to map these three entities into one?
Source:
public class Address
{
public int AddressId { get; set; }
public string AddressLine1 { get; set; }
public int CityId { get; set; }
public virtual City City { get; set; }
}
public class City
{
public int CityId { get; set; }
public string CityName { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public class Country
{
public int CountryId { get; set; }
public string CountryName { get; set; }
public virtual ICollection<City> Cities { get; set; }
}
Destination:
Public Class AddressViewModel
{
public int AddressId { get; set; }
public string AddressLine1 { get; set; }
public int CityId { get; set; }
public string CityName { get; set; }
public int CountryId { get; set; }
public string CountryName { get; set}
}
A couple of ways (at least). If you name your viewmodel fields differently it can happen by convention:
Public Class AddressViewModel
{
public int AddressId { get; set; }
public string AddressLine1 { get; set; }
public int CityCityId { get; set; }
[DisplayName("City Name")]
public string CityCityName { get; set; }
public int CityCountryCountryId { get; set; }
[DisplayName("Country Name")]
public string CityCountryCountryName { get; set}
}
If that's too ugly, you can do it in CreateMap:
Mapper.CreateMap<Address, AddressViewModel>()
.ForMember(dest => dest.CityId, opts => opts.MapFrom(src => src.City.CityId))
.ForMember(dest => dest.CityName, opts => opts.MapFrom(src => src.City.CityName))
.ForMember(dest => dest.CountryId, opts => opts.MapFrom(src => src.City.Country.CountryId))
.ForMember(dest => dest.CountryName, opts => opts.MapFrom(src => src.City.Country.CountryName));
http://automapper.codeplex.com/wikipage?title=Flattening&referringTitle=Home
Example to use Include() to query data in deeper levels:
public AddressViewModel GetAddressById(int id)
{
var result = applicationDbContext.Address
.Include(o=>o.City)
.Include(o=>o.City.Country)
.FirstOrDefault(x=>x.AddressId == id);
return mapper.Map<AddressViewModel>(result);
}

Categories

Resources