Class Customer
public class Customer
{
public int Id { get; set; }
public int PersonId { get; set; }
public int DiscountValue { get; set; }
public Person Person { get; set; }
public ICollection<Receipt> Receipts { get; set; }
}
Class Person
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDate { get; set; }
}
Class CustomerModel
public class CustomerModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public DateTime BirthDate { get; set; }
public int DiscountValue { get; set; }
public ICollection<int> ReceiptsIds { get; set; }
}
I need to create mapping that combines Customer and Person into CustomerModel.
public class AutomapperProfile : Profile
{
public AutomapperProfile()
{
CreateMap<(Customer, Person), CustomerModel>();
}
}
How can I combine Customer and Person?
You can just map from Customer to CustomerModel as:
Solution 1: Specify the property mapping from source to destination via .ForMember().
CreateMap<Customer, CustomerModel>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Person.Name))
.ForMember(dest => dest.Surname, opt => opt.MapFrom(src => src.Person.Surname))
.ForMember(dest => dest.BirthDate, opt => opt.MapFrom(src => src.Person.BirthDate));
Solution 2: Flattening Person model via .IncludeMembers().
cfg.CreateMap<Customer, CustomerModel>()
.IncludeMembers(src => src.Person);
cfg.CreateMap<Person, CustomerModel>();
Demo Solution 1 & 2 # .NET Fiddle
Related
I have these two classes:
public class QuizDto
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string UserToken { get; set; }
public List<int> AreasId { get; set; }
public List<QuizQuestionDto> Questions { get; set; }
}
public class Quiz
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string UserToken { get; set; }
public List<JoinQuizAndArea> AreasOfQuizzes { get; set; }
public List<QuizQuestion> Questions { get; set; }
}
public class JoinQuizAndArea
{
public int QuizId { get; set; }
public Quiz Quiz { get; set; }
public int AreaId { get; set; }
public AreaOfQuiz Area { get; set; }
}
public class AreaOfQuiz
{
public int Id { get; set; }
public string Area { get; set; }
public List<JoinQuizAndArea> AreasOfQuizzes { get; set; }
}
I need to map QuizDto to Quiz, to do so I need to map these two properties:
public class QuizDto
{
public int Id { get; set; }
...
...
public List<int> AreasId { get; set; }
...
}
to these two properties:
public class JoinQuizAndArea
{
public int QuizId { get; set; }
...
public int AreaId { get; set; }
....
}
Inorder to do so, I created the following Resolver:
public class CustomResolver : IValueResolver<QuizDto, Quiz, List<JoinQuizAndArea>>
{
public List<JoinQuizAndArea> Resolve(QuizDto source, Quiz destination, List<JoinQuizAndArea> member, ResolutionContext context)
{
var list = new List<JoinQuizAndArea>();
foreach(var areaId in source.AreasId)
{
var joinQuizAndArea = new JoinQuizAndArea();
joinQuizAndArea.AreaId = areaId;
joinQuizAndArea.QuizId = source.Id;
list.Add(joinQuizAndArea);
}
return list;
}
}
interface IValueResolver<in TSource, in TDestination,TDestMember>
{
TDestMember Resolve(TSource source, TDestination destination, TDestMember destMember, ResolutionContext context);
}
But when I try to configure the mapping profile:
public class QuizProfile:Profile
{
public QuizProfile()
{
CreateMap<Quiz, QuizDto>();
CreateMap<QuizDto, Quiz>()
.ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.Title))
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.UserToken, opt => opt.MapFrom(src => src.UserToken))
.ForMember(dest => dest.AreasOfQuizzes, opt=>opt.MapFrom<CustomResolver>())
.ForMember(dest => dest.Questions, opt => opt.MapFrom(src => src.Questions));
}
}
I got an error message:
CS0311 The type 'QuizzWorld.Mapping.Resolver.CustomResolver' cannot be used as type parameter 'TValueResolver' in the generic type or method 'IMemberConfigurationExpression.MapFrom()'. There is no implicit reference conversion from 'QuizzWorld.Mapping.Resolver.CustomResolver' to 'AutoMapper.IValueResolver'. QuizzWorld C:\Users\Sohaib\source\repos\QuizzWorld\Back End\QuizzWorld Back End\QuizzWorld\Mapping\QuizProfile.cs
plz, does anyone have an idea what the issue is exactly??
Thanks.
You have the compiler error because you have your own definition of IValueResolver interface which overrides the one from AutoMapper. Remove your IValueResolver interface or rename it. After that the compilation should succeed.
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 ));
From the nested Entity list we want to select an object and map it in the Dto object, but when we use the Automapper to filter for object which deleteDate is equal null and map it, for each column Automapper filter again on db. how to filter one time and map selected to Dto object
We need to store all the information in our database so use DeleteDate column with default value null. so we use one to many relation to store history of our data.
public class User
{
public Guid UserId { get; set; }
public string MobileNumber { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<CustomerDetail> CustomerDetails { get; set; }
}
public class CustomerDetail
{
public Guid CustomerDetailId { get; set; }
public float MaximumAmountPerTransaction { get; set; }
public float MaximumAmountPerDay { get; set; }
public bool IsConfirm { get; set; }
public Guid UserId { get; set; }
public virtual DateTimeOffset CreateDate { get; set; }
public virtual DateTimeOffset? DeleteDate { get; set; }
}
public class CustomerResponse
{
[Key]
public Guid CustomerId{ get; set; }
public string MobileNumber{ get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsConfirm { get; set; }
public float? MaximumAmountPerTransaction { get; set; }
public float? MaximumAmountPerDay { get; set; }
}
public class CustomerDomainProfile : Profile
{
public UserDomainProfile()
{
CreateMap<User, CustomerResponse>()
.ForMember(dest => dest.CustomerId,
opt => opt.MapFrom(src => src.UserId))
.ForMember(dest => dest.Country,
opt => opt.MapFrom(src => src.Country.CommonName))
.ForMember(dest => dest.IsConfirm,
opt => opt.MapFrom(src => src.CustomerDetails.FirstOrDefault(cd => cd.DeleteDate == null).IsConfirm))
.ForMember(dest => dest.MaximumAmountPerTransaction,
opt => opt.MapFrom(src => src.CustomerDetails.FirstOrDefault(cd => cd.DeleteDate == null).MaximumAmountPerTransaction))
.ForMember(dest => dest.MaximumAmountPerDay,
opt => opt.MapFrom(src => src.CustomerDetails.FirstOrDefault(cd => cd.DeleteDate == null).MaximumAmountPerDay))
}
}
I expect a query to the database and select the CustomerDetails with DeleteDate is null and map it, but the type of our define, for each column trying to query to database because
I expect that querying the database and selecting CustomerDetails with DeleteDate is null and its map, but our definition, for each column, is trying to query the database because it can not recognize that they are from a same table. How can we identify them that have fallen from a row to reduce the query? is any other solution or idea?
I have this structure:
public class UserEntity
{
public long Id { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
public ComplexObject TimeZone { get; set; }
}
public class UserQueryResult
{
public UserEntity User { get; set; }
public ObjectId AccountId { get; set; }
}
public class UserDto
{
public long Id { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
public string TimeZoneId { get; set; }
public string AccountId { get; set; }
}
I have UserEntity to UserDto mapping like this:
CreateMap<UserEntity, UserDto>()
.ForMember(dest => dest.TimeZoneId, opt => opt.ResolveUsing<UserTimeZoneResolver>())
.ForMember(dest => dest.AccountId, opt => opt.Ignore());
As you can see, there's a resolver from UserEntity to UserDto. Now, if I want to map UserQueryResult to UserDto, how could I reuse the above mapper without the need to map all properties manually?
CreateMap<UserQueryResult, UserDto>()
.ForMember(dest => dest.AccountId, opt => opt.MapFrom(src => src.AccountId.ToString()))
.// use the UserEntity to UserDto map?
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.