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 ));
Related
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)));
}
I have been trying to map my entities to my viewmodels with AutoMapper. And faced problems with nested collection mapping.
The Source
public class Consignment
{
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<ConsignmentLine> ConsignmentLines { get; set; }
public ICollection<ConsignmentDocument> ConsignmentDocuments { get; set; }
}
public class ConsignmentLine
{
public Guid Id { get; set; }
public Guid ConsignmentId { get; set; }
public ICollection<ConsignmentDocument> ConsignmentDocuments { get; set; }
}
public class ConsignmentDocument
{
public Guid Id { get; set; }
public Guid ConsignmentId { get; set; }
public Guid ConsignmentLineId { get; set; }
public string DocumentName { get; set; }
}
public class ConsignmentLineViewModel
{
public Guid Id { get; set; }
public Guid ConsignmentId { get; set; }
public ICollection<ConsignmentDocumentViewModel> ConsignmentDocuments { get; set; }
}
public class ConsignmentDocumentViewModel
{
public Guid Id { get; set; }
public Guid ConsignmentId { get; set; }
public Guid ConsignmentLineId { get; set; }
public string DocumentName { get; set; }
}
The destination
public class ConsignmentDetailsViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<ConsignmentLineViewModel> ConsignmentLines { get; set; }
public ICollection<ConsignmentDocumentViewModel> ConsignmentDocuments { get; set; }
}
I can map consignmentDocuments for each consignment very easily but while mapping consignmentlines for each consignment i am getting an "AutoMapper Exception". I know the exception is being generated because of each consignmentLine has it's own collection of consignmentDocuments.
Right now my automapper profile
CreateMap<Consignment, ConsignmentDetailsViewModel>()
.ForMember(vm => vm.consignmentLineViewModel, opt => opt.MapFrom(model => model.ConsignmentLine.ToList()))
.ForMember(vm => vm.consignmentDocumentViews, opt => opt.MapFrom(model => model.ConsignmentDocument.ToList()));
How can I map all of them to the ConsignmentViewModel class?
Resolved the problem.
The solution is to create a map for ConsignmentLine to get the collection of ConsignmentDocuments.
CreateMap<Consignment, ConsignmentDetailsViewModel>()
.ForMember(vm => vm.consignmentLineViewModel, opt => opt.MapFrom(model => model.ConsignmentLine))
.ForMember(vm => vm.consignmentDocumentViews, opt => opt.MapFrom(model => model.ConsignmentDocument));
CreateMap<ConsignmentLine, ConsignmentLineViewModel>()
.ForMember(vm => vm.consignmentDocumentViews, opt => opt.MapFrom(model => model.ConsignmentDocument));
If you act simply without thinking too complex in AutoMapper transactions, you can perform all your transactions.
Example:
CreateMap<Consignment, ConsignmentDetailsViewModel>();
CreateMap<ConsignmentLine, ConsignmentLineViewModel>();
CreateMap<ConsignmentDocument, ConsignmentDocumentViewModel>();
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?
I have a simple class called Supplier which has contacts and contact can have addresses. right now we are using only 1 contact and 1 address (line1 to line4) in that contact. In future we might use multiple contacts having multiple addresses. below is my class
public class SupplierDto
{
public string Name { get; set; }
public string Alias { get; set; }
public int? SupplierTypeId { get; set; }
public int? WebclicsManufacturerId { get; set; }
public string SAPCode { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Line4 { get; set; }
public int CountryId { get; set; }
public string PostalCode { get; set; }
public string ContactName { get; set; }
public string ContactEmail { get; set; }
public string ContactTelephone { get; set; }
public string ContactJobTitle { get; set; }
}
My Supplier class is a bit complex, so I am trying to map from Supplier to DTO and below is my mapping.
CreateMap<Supplier, SupplierDto>()
.ForMember(dest => dest.Line1, options => options.MapFrom(source => source.SupplierContacts.First().Contact.EntityAddresses.First().Address.Line1))
.ForMember(dest => dest.Line2, options => options.MapFrom(source => source.SupplierContacts.First().Contact.EntityAddresses.First().Address.Line2))
.ForMember(dest => dest.Line3, options => options.MapFrom(source => source.SupplierContacts.First().Contact.EntityAddresses.First().Address.Line3))
.ForMember(dest => dest.Line4, options => options.MapFrom(source => source.SupplierContacts.First().Contact.EntityAddresses.First().Address.Line4))
.ForMember(dest => dest.CountryId, options => options.MapFrom(source => source.SupplierContacts.First().Contact.EntityAddresses.First().Address.CountryId))
.ForMember(dest => dest.PostalCode, options => options.MapFrom(source => source.SupplierContacts.First().Contact.EntityAddresses.First().Address.PostalCode))
.ForMember(dest => dest.ContactName, options => options.MapFrom(source => source.SupplierContacts.First().Contact.Name))
.ForMember(dest => dest.ContactEmail, options => options.MapFrom(source => source.SupplierContacts.First().Contact.Email))
.ForMember(dest => dest.ContactTelephone, options => options.MapFrom(source => source.SupplierContacts.First().Contact.Telephone))
.ForMember(dest => dest.ContactJobTitle, options => options.MapFrom(source => source.SupplierContacts.First().Contact.JobTitle));
As you can see I have custom logic for each column. Now problem is if there is no contact/address, code breaks because I am using
First()
from LINQ, is there a better way to check if contacts exists then do mapping and if it has addresses then proceed with address mapping?
Just create an ContactDto and add it to the SupplierDto, then move all contact relevant properties to the ContactDto.
public class ContactDto
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Line4 { get; set; }
public int CountryId { get; set; }
public string PostalCode { get; set; }
public string ContactName { get; set; }
public string ContactEmail { get; set; }
public string ContactTelephone { get; set; }
public string ContactJobTitle { get; set; }
}
public class SupplierDto
{
public string Name { get; set; }
public string Alias { get; set; }
public int? SupplierTypeId { get; set; }
public int? WebclicsManufacturerId { get; set; }
public string SAPCode { get; set; }
public ContactDto Contact { get; set; }
}
Then the mapping should look something like this
CreateMap<Supplier, SupplierDto>()
.ForMember(dest => dest.Contact, options => options.MapFrom(source => source.SupplierContacts.FirstOrDefault()));
If Contact is null then AutoMapper didn't try to map it. If you want in the Future support multiple Contacts on the Supplier, then just change the ContactDto Contact Property to a List<ContactDto> and remove the .FirstOrDefault() in the Mapping.
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);
}