I have next enteties
public class TagDTO
{
public int Id { get; set; }
public string Description { get; set; }
public List<ImageDTO> Images { get; set; }
}
public class ImageDTO
{
public int Id { get; set; }
public List<TagDTO> Tags { get; set; }
}
And when I'm mapping from Image to ImageDTO i do not need List<Images> in TagDTO class. But in other cases this property is necessary. Can I configure in AutoMapper to Ignore List<ImagesDTO> Images, like this
CreateMap<Image, ImageDTO>().ForMember(x => x.Tags.Select(p=>p.Images),
opts => opts.Ignore());
Related
An interesting problem of this nature. I'm trying to map List to List. That is, to compare two homogeneous objects.
However, the mapper throws me an Exception
Missing type map configuration or unsupported mapping.
I would be grateful for any help! I can't solve the problem all day.
CreateMap<List<GrammarQuestionDTO>, TestDTO>()
.ForMember(t => t.GrammarQuestion, map => map.MapFrom(source => source))
.ForAllOtherMembers(x => x.Ignore());
public class GrammarQuestionDTO
{
public int Id { get; set; }
public LevelType LevelType { get; set; }
public QuestionType QuestionType { get; set; } = QuestionType.Grammar;
public string Question { get; set; }
public List<AnswerDTO> Answers { get; set; }
}
public class TestDTO
{
public int Id { get; set; }
public List<GrammarQuestionDTO> GrammarQuestion { get; set; }
public List<AuditionQuestionDTO> AuditionQuestion { get; set; }
public string EssayTopic { get; set; }
public string SpeakingTopic { get; set; }
}
Using the following entities
public class User
{
public Guid Id { get; set; }
public string Username { get; set; }
}
public class GeneralEntity
{
public Guid Id { get; set; }
public User CreatedByUser { get; set; }
public User DeletedByUser { get; set; }
}
How do I flatten this to the GeneralEntityDto below?
public class GeneralEntityDto
{
public Guid Id { get; set; }
public string CreatedByUsername { get; set; }
public string DeletedByUsername { get; set; }
}
I have tried setting up my mappings as seen below but it fails with a complaint about "CreatedByUsername" and "DeletedByUsername" not being mapped.
protected void Configure()
{
CreateMap<GeneralEntity, GeneralEntityDto>()
.ForMember(dest => dest.CreatedByUsername,
opt => opt.MapFrom(src => src.CreatedByUser.Username))
.ForMember(dest => dest.DeletedByUsername, opt =>
opt.MapFrom(src => src.DeletedByUser.Username));
}
You can use the naming convention that automapper provides.
Basically if you include the exact string of the property name of the source Object you do not have to add ForMember() automapper is clever enough to do it automatically.
That means for example :
public class GeneralEntity
{
public Guid Id { get; set; }
public User CreatedBy { get; set; } // renaming just for simplicity
public User DeletedBy { get; set; } // renaming just for simplicity
}
public class GeneralEntityDto
{
public Guid Id { get; set; }
public string CreatedByUsername { get; set; }
public string DeletedByUsername { get; set; }
}
Reference also to these:
http://docs.automapper.org/en/stable/Flattening.html
AutoMapper TwoWay Mapping with same Property Name
I have two class TenantRestrictSourceEntity, TenantRestrictSource and mapper profile
CreateMap<TenantRestrictSourceEntity, TenantRestrictSource>()
.ForMember(dest => dest.Tenant, opt => opt.Ignore());
public class TenantRestrictSourceEntity
{
public string SourceType { get; set; }
public bool? Enable { get; set; }
public int TenantId { get; set; }
}
public sealed class TenantRestrictSource
{
public int Id { get; set; }
public string SourceType { get; set; }
public bool Enable { get; set; }
public int TenantId { get; set; }
public Tenant Tenant { get; set; }
}
When I map one TenantRestrictSourceEntity to one TenantRestrictSource with Mapper.Map(tenantRestrictSourceEntity, tenantRestrictSource). Everything works fine. Tenant property was ignored correctly.
But when I try to map a list TenantRestrictSourceEntity to a list TenantRestrictSource with Mapper.Map(tenantRestrictSourceEntities, tenantRestrictSources) Tenant property is always null.
How can I ignore that property when mapping a list object?
I want to map my DTO to an entity. The only difference between the two is my dto's use List as collection type and the entities use HashSet. How can I configure Automapper to automatically map to a HashSet when it encounters an ICollection? Currently it just replaces the hashset in the entity with a List.
Example classes and mapping:
cfg.CreateMap<MachineDto, Machine>(MemberList.Source)
cfg.CreateMap<Machine, MachineDto>(MemberList.Destination)
public class Machine
{
public Machine()
{
Segment = new HashSet<Segment>();
}
public long ID { get; set; }
public string Name { get; set; }
public ICollection<Segment> Segment { get; set; }
}
public class Segment
{
public Segment()
{
}
public long ID { get; set; }
public long MachineID { get; set; }
public string Serial { get; set; }
}
public class MachineDto
{
public MachineDto()
{
Segment = new List<SegmentDto>();
}
public long ID { get; set; }
public string Name { get; set; }
public ICollection<SegmentDto> Segment { get; set; }
}
public class SegmentDto
{
public SegmentDto()
{
}
public long ID { get; set; }
public string Serial { get; set; }
}
After a lot of fiddling around with the AfterMap() I found the UseDestinationValue option, when defined it will reuse the existing HashSet instead of replacing the ICollection with a List.
cfg.CreateMap<MachineDto, Machine>(MemberList.Source)
.ForMember(dest => dest.Segment, opt => opt.UseDestinationValue());
I've tried numerous examples on here and from the automapper wiki and I am still unable to get this issue resolved. I am trying to map a nested object and a nested collection and no matter what I do it always throws an error. The only way I can get the controller to return data is by turning on option.ignore for the two properties.
These are the business layer objects I am trying to map
public class LocationBL
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
public string Country { get; set; }
public DbGeography Coordinates { get; set; }
public int LocationType_Id { get; set; }
public virtual LocationTypeBL LocationType { get; set; }
public virtual ICollection<SportBL> Sports { get; set; }
}
public class LocationTypeBL
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<LocationBL> Locations { get; set; }
}
public class SportBL
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<LocationBL> Locations { get; set; }
public virtual ICollection<UserBL> Users { get; set; }
}
These are the data layer objects
public class Location : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("Company")]
public int? CompanyId { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
public string Country { get; set; }
[Required]
public DbGeography Coordinates { get; set; }
[ForeignKey("LocationType")]
public int LocationType_Id { get; set; }
public virtual LocationType LocationType { get; set; }
public virtual ICollection<Sport> Sports { get; set; }
public virtual Company Company { get; set; }
}
public class LocationType : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Sport : EntityData
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Location> Locations { get; set; }
public virtual ICollection<User> Users { get; set; }
}
This is my mapping profile
public class LocationProfile : Profile
{
public LocationProfile()
{
CreateMap<LocationType, LocationTypeBL>();
CreateMap<LocationTypeBL, LocationType>();
CreateMap<Location, LocationBL>()
.ForMember(Dest => Dest.Sports,
opt => opt.MapFrom(src => src.Sports))
.ForMember(Dest => Dest.LocationType,
opt => opt.MapFrom(src => src.LocationType));
CreateMap<LocationBL, Location>()
.ForMember(Dest => Dest.Sports,
opt => opt.MapFrom(src => src.Sports))
.ForMember(Dest => Dest.LocationType,
opt => opt.MapFrom(src => src.LocationType));
}
}
UPDATE *******
This is my LocationType profile
public class LocationTypeProfile : Profile
{
public LocationTypeProfile()
{
CreateMap<LocationType, LocationTypeBL>();
CreateMap<LocationTypeBL, LocationType>();
}
}
This is my Sport profile
public class SportProfile : Profile
{
public SportProfile()
{
CreateMap<Sport, SportBL>();
CreateMap<SportBL, Sport>();
}
}
Not sure if it matters but this is an Azure Mobile App backend using Autofac, WebAPI, and OWIN. This is my first time using AutoMapper and Autofac so please forgive me as I am still learning. The profiles are all registered and if I set the nested objects to ignore, the controller returns the proper data.
Thank you in advance!!!
You are almost there. You need to instruct AutoMapper on how to map the nested objects as well. So you need to create a map for the Sport to SportBL, and vice-versa, also.
// use ForMember if needed, but you know how to do that so I won't
// show it.
CreateMap<Sport, SportBL>();
Then AutoMapper will use that mapping when it mapping nested complex types.
Another note, if your classes have the same properties, you can just call the ReverseMap() method and it will do bidirectional mapping for you.
So instead of this:
CreateMap<LocationType, LocationTypeBL>();
CreateMap<LocationTypeBL, LocationType>();
You can just do this to accomplish the same thing:
Mapper.CreateMap<LocationType, LocationTypeBL>().ReverseMap();