I have the following mapping:
CreateMap<LayoutRequest, Layout>();
CreateMap<Layout, LayoutRequest>()
.ForMember(m => m.Settings, opt => opt.Ignore());
It works fine but are we able to do it by single line? I thought it should solve my case:
CreateMap<LayoutRequest, Layout>()
.ForSourceMember(m => m.Settings, opt => opt.Ignore());
But it doesn't work. It says there is no mapping for Settings
AutoMapper has a "ReverseMap" feature that can be used like below.
CreateMap<Layout, LayoutRequest>()
.ForMember(m => m.Settings, opt => opt.Ignore())
.ReverseMap();
Related
I have classes which have the usual CreatedDate, CreatedById, EditedDate, EditedById and etc. fields on which I ignore when mapping from Domain models -> Entity models (they are populated later by the database).
My mappings are now littered with mapping ignore looking a bit like
CreateMap<UpdateProvider, ProviderInstance>()
.ForMember(e => e.Id, opt => opt.Ignore())
.ForMember(e => e.CreatedDate, opt => opt.Ignore())
.ForMember(e => e.CreatedById, opt => opt.Ignore())
.ForMember(e => e.EditedDate, opt => opt.Ignore())
.ForMember(e => e.EditedById, opt => opt.Ignore())
.ForMember(e => e.ArchivedDate, opt => opt.Ignore())
.ForMember(e => e.ArchivedById, opt => opt.Ignore());
Can I centralize this in a single method to adhere to the DRY principle. If it helps each of these fields have interfaces called IIdentifiable, ICreateable, IEditable, IArchiveable.
I was hoping to just create an extension method of something like .IgnoreDbGeneratedFields<TDestination>()
An extension method along the following lines should work:
public static IMappingExpression<T1, T2> IgnoreDbGeneratedFields<T1, T2>(this IMappingExpression<T1, T2> e)
where T2 : IIdentifiable, ICreateable, IEditable, IArchiveable
{
return e
.ForMember(x => x.Id, opt => opt.Ignore())
.ForMember(x => x.CreatedDate, opt => opt.Ignore())
.ForMember(x => x.CreatedById, opt => opt.Ignore())
.ForMember(x => x.EditedDate, opt => opt.Ignore())
.ForMember(x => x.EditedById, opt => opt.Ignore())
.ForMember(x => x.ArchivedDate, opt => opt.Ignore())
.ForMember(x => x.ArchivedById, opt => opt.Ignore());
}
I am getting this error and I do not understand why. I am trying to map a Client object to a ClaimClient object (shown below):
public class ClaimClient : Client
{
public int ClaimClientID { get; set; }
public bool IsContactable { get; set; }
}
As you can see the ClaimClient will contain all the client properties plus the additional properties shown above. My mapper:
x.CreateMap<Client, ClaimClient>();
The only thing I can think of is it's expecting me to define a mapping between Client and Client? Any help appreciated
EDIT:
Mapper now as below but still getting same error:
x.CreateMap<Client, ClaimClient>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.LastName))
.ForMember(dest => dest.Title, opt => opt.MapFrom(src => src.Title))
.ForPath(dest => dest.pAddress, opt => opt.MapFrom(src => src.pAddress))
.ForMember(dest => dest.IsLead, opt => opt.MapFrom(src => src.IsLead))
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.FirstName))
.ForMember(dest => dest.HasOptions, opt => opt.MapFrom(src => src.HasOptions))
.ForPath(dest => dest.Options, opt => opt.MapFrom(src => src.Options));
x.CreateMap<Client, Client>();
I had the following mapping in my AutoMapper profile, and It was working:
CreateMap<KeyValuePair<int, string>, SelectListItem>()
.ForMember(m => m.Selected, opt => opt.Ignore())
.ForMember(m => m.Text, opt => opt.MapFrom(c => c.Value))
.ForMember(m => m.Value, opt => opt.MapFrom(c => c.Key.ToString()));
CreateMap<KeyValuePair<short, string>, SelectListItem>()
.ForMember(m => m.Selected, opt => opt.Ignore())
.ForMember(m => m.Text, opt => opt.MapFrom(c => c.Value))
.ForMember(m => m.Value, opt => opt.MapFrom(c => c.Key.ToString()));
After updating to Veriosn 5.1.1 I'm getting the following error in AutoMapper initializing:
Instance property 'Item(KeyValuePair`2)' is not defined for type 'System.Collections.Generic.Dictionary`2[System.Object,System.Object]'
By commenting above mapping line I don't get error anymore but I need them.
How can I fix it?
I (am forced to) use AutoMapper version 1.1.0.188. I have a base class SchufaBaseFeature and a derived class SchufaFeature.
public partial class SchufaFeature : SchufaBaseFeature
{//some code here}
Why is Include not working as I would expect it to ?
This is what I have done with AutoMapper (Mapping to DataBase):
//TODO include does not work as it should!
Mapper.CreateMap<SchufaBaseFeature, CFSCHUFAFEATURE>()
.ForMember(dest => dest.FEATUREWITHOUTBIRTHDATE, opt => opt.MapFrom(src => GetSpecified(EnumToBool(src.featureWithoutBirthdate), src.featureWithoutBirthdateSpecified)))
.ForMember(dest => dest.OWNFEATURE, opt => opt.MapFrom(src => GetSpecified(src.ownFeature, src.ownFeatureSpecified)))
.Include<SchufaFeature, CFSCHUFAFEATURE>()
;
Mapper.CreateMap<SchufaFeature, CFSCHUFAFEATURE>()
.ForMember(dest => dest.DATE, opt => opt.MapFrom(src => GetDate(src.date)))
.ForMember(dest => dest.AMOUNT, opt => opt.MapFrom(src => src.amount.amount))
.ForMember(dest => dest.AMOUNTCUR, opt => opt.MapFrom(src => src.amount.currency))
.ForMember(dest => dest.NUMBEROFINSTALLEMENTS, opt => opt.MapFrom(src => TryParseToInt(src.numberOfInstallments)))
.ForMember(dest => dest.INSTALLMENTTYPE, opt => opt.MapFrom(src => src.installmentType))
;
It is correctly mapping FEATUREWITHOUTBIRTHDATE and OWNFEATURE, but the Include isn't called. When I run debugger the second CreateMap is never called.
I have checked the Documentation here (AutoMapper Github Inheritance) and I still can't understand what I am doing wrong. What might be the problem ? Is it me or is there a bug in this version of AutoMapper ?
You might need to switch the order in which you create maps. Include has a....feature in which it checks existing maps for configuration. If that existing map isn't there yet, you'll need to switch the order.
This is all fixed in 5.0 of course but you're stuck :)
I solved my problem by using .ConstructUsing. In the first version of AutoMapper the Include does not work as expected, switching the order did nothing for me . Below is my source code:
Mapper.CreateMap<SchufaFeature, CFSCHUFAFEATURE>()
.ForMember(dest => dest.FEATUREWITHOUTBIRTHDATE, opt => opt.Ignore())
.ForMember(dest => dest.OWNFEATURE, opt => opt.Ignore())
.ForMember(dest => dest.DATE, opt => opt.MapFrom(src => GetDate(src.date)))
.ForMember(dest => dest.NUMBEROFINSTALLEMENTS, opt => opt.MapFrom(src => TryParseToInt(src.numberOfInstallments)))
.ForMember(dest => dest.INSTALLMENTTYPE, opt => opt.MapFrom(src => src.installmentType))
.ForMember(dest => dest.AMOUNT, opt => opt.Ignore())
.AfterMap((dto, cfschufafeature) => { Mapper.Map(dto.amount, cfschufafeature); })
;
Mapper.CreateMap<SchufaTextFeature, CFSCHUFAFEATURE>()
.ForMember(dest => dest.FEATUREWITHOUTBIRTHDATE, opt => opt.Ignore())
.ForMember(dest => dest.OWNFEATURE, opt => opt.Ignore())
;
//include does not work in this AutoMapper version as expected, that is why we use ConstructUsing
Mapper.CreateMap<SchufaBaseFeature, CFSCHUFAFEATURE>()
.ConstructUsing(feature =>
{
var schufaFeature = feature as SchufaFeature;
var schufaTextFeature = feature as SchufaTextFeature;
CFSCHUFAFEATURE result = new CFSCHUFAFEATURE();
if (schufaFeature != null)
Mapper.Map(schufaFeature, result);
if (schufaTextFeature != null)
Mapper.Map(schufaTextFeature, result);
return result;
})
.ForMember(dest => dest.FEATUREWITHOUTBIRTHDATE, opt => opt.MapFrom(src => GetSpecified(EnumToBool(src.featureWithoutBirthdate), src.featureWithoutBirthdateSpecified)))
.ForMember(dest => dest.OWNFEATURE, opt => opt.MapFrom(src => GetSpecified(EnumToBool(src.ownFeature), src.ownFeatureSpecified)))
;
I have some objects with a large number of properties. When I started using AutoMapper I was attempting to just map a few nested objects to understand how it works. All the time I thought it would map over properties with the same name at the source and the destination. However it seems that once I have some ForMember() rules it only maps the properties for which I have rules.
Is there a way to only a specify a few rules, where the source and destination object differ? Or do I have to be explicit and map every property?
Mapper.CreateMap<MessageWireFormat, Message>()
.ForMember(dest => dest.PlainBody, opt => opt.MapFrom(src => src.Body.Plain))
.ForMember(dest => dest.ParsedBody, opt => opt.MapFrom(src => src.Body.Parsed))
.ForMember(dest => dest.RichBody, opt => opt.MapFrom(src => src.Body.Rich))
.ForMember(dest => dest.Excerpt, opt => opt.MapFrom(src => src.ContentExcerpt))
.ForMember(dest => dest.AttachmentCount, opt => opt.MapFrom(src => src.Attachments.Length))
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id))
.ForMember(dest => dest.Url, opt => opt.MapFrom(src => src.Url))
.ForMember(dest => dest.WebUrl, opt => opt.MapFrom(src => src.WebUrl))
.ForMember(dest => dest.NetworkId, opt => opt.MapFrom(src => src.NetworkId))
.ForMember(dest => dest.GroupId, opt => opt.MapFrom(src => src.GroupId))
.ForMember(dest => dest.SystemMessage, opt => opt.MapFrom(src => src.SystemMessage))
.ForMember(dest => dest.Privacy, opt => opt.MapFrom(src => src.Privacy))
.ForMember(dest => dest.DirectMessage, opt => opt.MapFrom(src => src.DirectMessage))
.ForMember(dest => dest.SenderType, opt => opt.MapFrom(src => src.SenderType))
.ForMember(dest => dest.SenderId, opt => opt.MapFrom(src => src.SenderId))
.ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(src => src.CreatedAt))
.ForMember(dest => dest.ClientType, opt => opt.MapFrom(src => src.ClientType))
.ForMember(dest => dest.ClientUrl, opt => opt.MapFrom(src => src.ClientUrl))
.ForMember(dest => dest.RepliedToId, opt => opt.MapFrom(src => src.RepliedToId))
.ForMember(dest => dest.Language, opt => opt.MapFrom(src => src.Language));
Holy moly. Nearly all of those mappings are unnecessary. MapFrom is only intended when names don't match, not when they do. Even when they don't match, I'd need a really good reason to not have "BodyPlain", which would map without configuration, instead of "PlainBody", which doesn't match "Body.Plain".