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);
}
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 three tables:
Member, business and business address
I'm able to fetch the business with member using Include, but I'm trying to get businessAddress, it is asking for direct relationship i guess.
Here is my models:
[Table("member")]
public partial class Member
{
public Member()
{
Business = new HashSet<Business>();
// BusinessAddress = new HashSet<BusinessAddress>();
}
[Key]
public int memberId { get; set; }
public int chapterid { get; set; }
public string title { get; set; }
public string firstname { get; set; }
public string lastname { get; set; }
public bool IsActive { get; set; }
public string classification { get; set; }
public int SortOrder { get; set; }
public virtual ICollection<Business> Business { get; set; }
// public virtual ICollection<BusinessAddress> BusinessAddress { get; set; }
}
Business
[Table("Business")]
public partial class Business
{
public Business()
{
BusinessAddress = new HashSet<BusinessAddress>();
}
[Key]
public int BusinessID { get; set; }
public int? categoryid { get; set; }
public int? subcategoryid { get; set; }
public int memberid { get; set; }
public string businessname { get; set; }
public string dealingin { get; set; }
public int? sortOrder { get; set; }
[ForeignKey("memberid")]
public Member Member { get; set; }
public ICollection<BusinessAddress> BusinessAddress { get; set; }
}
BusinessAddress
[Table("BusinessAddress")]
public partial class BusinessAddress
{
[Key]
public int businessaddressid { get; set; }
public int businessid { get; set; }
[ForeignKey("businessid")]
public virtual Business Business { get; set; }
public string address { get; set; }
}
Below is my EF query:
var list = _dbContext.Member.Include("Business").OrderByDescending(x => x.SortOrder).ThenBy(x => x.firstname).ToList();
I want to get Member with business and BusinessAddresses. I have tried Include("BusinesADdress") that didn't work, Help me please.
Try using Include accepting lambda selector followed by ThenInclude:
var list = _dbContext.Member
.Include(m => m.Business)
.ThenInclude(b => b.BusinessAddress)
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.firstname)
.ToList();
Also you can just append all needed relations via . in the Include call but in general I would recommend against it cause the first approach is type safe:
var list = _dbContext.Member
.Include("Business.BusinessAddress")
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.firstname)
.ToList();
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 ));
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 following database objects:
public class LinkedContact
{
public int LinkedContactID { get; set; }
public Nullable<int> ContactID { get; set; }
public Nullable<int> ContactTypeID { get; set; }
public Nullable<bool> Deleted { get; set; }
public virtual Contact Contact { get; set; }
public virtual ContactType ContactType { get; set; }
}
public class Contact
{
public Contact()
{
this.LinkedContact = new HashSet<LinkedContact>();
}
public int ContactID { get; set; }
public string DisplayName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<bool> Deleted { get; set; }
public virtual ICollection<LinkedContact> LinkedContact { get; set; }
}
public class ContactType
{
public ContactType()
{
this.LinkedContact = new HashSet<LinkedContact>();
}
public int ContactTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<LinkedContact> LinkedContact { get; set; }
}
I want to map it into following DTO
public class ContactDTO
{
public int ContactID { get; set; }
public string DisplayName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ContactTypeDTO ContactType { get; set; }
}
public class ContactTypeDTO
{
public int ContactTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
So basically, the Contact Type from Linked Contact should map to Contact DTO. End user will only see Contact View Model and is not aware of Linked Contact and hence the structure. Can anyone help me with the mapping configuration. I have tried the following with no luck
CreateMap<Contact, ContactDTO>().ReverseMap();
CreateMap<LinkedContact, ContactDTO>()
CreateMap<ContactType, ContactTypeDTO>().ReverseMap();
look through this link , there is a good sample
CreateMap<LinkedContact, ContactDTO>()
.ForMember(dest => dest.DisplayName, opts => opts.MapFrom(src => src.Contact.DisplayName))
.ForMember(dest => dest.FirstName, opts => opts.MapFrom(src => src.Contact.FirstName))
.ForMember(dest => dest.LastName, opts => opts.MapFrom(src => src.Contact.LastName))
another option:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Contact, ContactDTO>().ReverseMap();
cfg.CreateMap<ContactType, ContactTypeDTO>().ReverseMap();
cfg.CreateMap<LinkedContact, ContactDTO>().ConvertUsing(src =>
{
var contact = Mapper.Map<Contact, ContactDTO>(src.Contact);
contact.ContactType = Mapper.Map<ContactType, ContactTypeDTO>(src.ContactType);
return contact;
});
});
Finally I used the below configuration which mapped both Contact and Contact Type. Leaving it here for people looking for answer to the same thing:
CreateMap<LinkedContact, ContactDTO>().ConvertUsing((src, dest, context) =>
{
dest = context.Mapper.Map<ContactDTO>(src.Contact);
dest.ContactType = context.Mapper.Map<ContactTypeDTO>(src.ContactType);
return dest;
});
CreateMap<Contact, ContactDTO>().ReverseMap();
CreateMap<ContactType, ContactTypeDTO>().ReverseMap();