I'd like to send some additional information to Automapper so I can use them in the CreateMap. It seems that I have to use MappingOperatingOption and Items.
So my call is like this:
var obj = Mapper.Map<class>(x, o => o.Items.Add("data", 23));
The problem is that I cannot access that value in the MapFrom.
Mapper.CreateMap<ClassA, ClassB>()
.ForMember(x => x.FieldA, o => o.MapFrom(d =>
//accessing item here))
There's very little documentation about Automapper and I didn't come up with anything, any guidance is welcome.
Use ResolveUsing instead of MapFrom like this:
Mapper.CreateMap<ClassA, ClassB>()
.ForMember(dst => dst.FieldA,
opt =>
opt.ResolveUsing((resolution_result, src) =>
(int)resolution_result.Context.Options.Items["data"] + src.FieldB));
I am using (int)resolution_result.Context.Options.Items["data"] + src.FieldB just as an example here. You can read any piece of data from resolution_result.Context.Options.Items and use it as you like.
Related
Is it possible to resolve a few destination properties from one source property using AutoMapper?
The obvious way to go is to do like this:
CreateMap<Source, Destination>
.ForMember(d => d.dest1, opt => opt.MapFrom(s => s.sour["dest1"]))
.ForMember(d => d.dest2, opt => opt.MapFrom(s => s.sour["dest2"]))
...
.ForMember(d => d.dest10, opt => opt.MapFrom(s => s.sour["dest10"]))
But is there maybe something like a custom resolver which would allow to write a method which would perform the assignment of multiple destination properties using one (or maybe even a few) source property (properties)?
I am relatively new to Automapper and just want to make sure I am not missing a shorter way to do this. I have a field in the database that when it is null, the value in the corresponding model is set to the string literal "None". I would like to do that logic in reverse when saving back to the database using the same mapperconfiguration if possible. Here is the current code (field in question is the last ".ForMember"):
var mapperConfiguration = new MapperConfiguration(cfg => cfg.CreateMap<Location, LocationModel>()
.ForMember(f => f.Name, db => db.MapFrom(f => f.LocationName))
.ForMember(f => f.Description, db => db.MapFrom(f => f.LocationDescription))
.ForMember(f => f.ERPCode, db => db.MapFrom(f => f.WarehouseCode))
.ForMember(f => f.ERPCodeQBID, db => db.MapFrom(f => f.WarehouseCodeQBID))
.ForMember(f => f.DefaultDispatchType, opt => opt.NullSubstitute("None")).ReverseMap());
The only way I have figured out to have "None" mapped back to null is to create a second map and not bother to reverse the one above. If there is a way to achieve this, please let me know.
You can chain the .ForMember() right after .ReverseMap() using a fluent syntax, which then becomes a mapping configuration of the LocationModel to Location
I am using Auto Mapper to map source to destination object, I have configured my mapper like this:
Mapper.Initialize(cfg => {
cfg.CreateMap< SourceModel, DestModel>();
}
This source and dest object mapping is being used in many places, now in some cases, I have to ignore one of source model field, but not for all places. I could do like this:
CreateMap< SourceModel, DestModel>()
.ForMember(x => x.CreatedDateTime, opt => opt.Ignore());
But this will ignore CreatedDateTime property for all scenario, so I want to do it inline only.
Mapper.Map< DestModel>(sourceObject); //Here I want to ignore one property.
Please help me how I can achieve this.
Sounds like you need conditional mapping.
This answer on SO shows how to use it and the documentation can be found here.
example usage:
Mapper.CreateMap<SourceModel, DestModel>()
.ForMember(dest => dest.CreatedDateTime, opt => opt.Condition(source => source.Id == 0))
I'd like to check if a property is still null after a generic ResolveUsing using a IMemberValueResolver. I tried AfterMap but it did not apply after a ResolveUsing on a collection, so I thought that AddTransform might be more appropriate.
Based on the existing AutoMapper unit tests, I can see that it is possible to override the destination property:
p.CreateMap<Source, Dest>()
.ForMember(d => d.Value, opt => opt.AddTransform(d => d + ", seriously"));
Would it be possible to get access to the source object inside AddTransform to extract a value from that object to override the destination?
This is what I'm basically trying to do:
cfg.CreateMap<Foo, Bar>()
.ForMember(d => d.Description, opts =>
{
opts.ResolveUsing<LocalizeResolver, ResourceType>(src => src.ResourceType);
opts.AddTransform(d => "whatever"); // src.Description??
})
.AfterMap((src, dst) => {
// this never works
if (string.IsNullOrWhiteSpace(dst.Description))
{
dst.Description = src.Description;
}
});
Is it possible in AutoMapper to ignore certain properties while mapping a list?
For example, I have two classes Metadata and MetadataInput.
Both have the same fields except for destination, "MetadataInput", which has an extra field.
Mapper.CreateMap <IList<Metadata>, IList<MetadataInput>>()
I've tried to use the formember option but it generates errors, probably because the property cannot be used when you want to map a list? If yes, is there alternative solution?
As Darin Dimitrov suggested, you should not try and map lists or collections.
If you have a 1 -> 1 relationship between them all, just make a map like:
Mapper.CreateMap<Metadata, MetadataInput>().ForMember(s => s.Property, t => t.Ignore());
Then you could use your list and select it to the other list.
var metadataList = new List<Metadata>();
var meatadataInputList = metadataList.Select(p => Mapper.Map<MetadataInput>(p).ToList();
Use this mapper configuration to get the desired result:
Mapper.CreateMap<Output, Input>().ForMember(s => s.InputProperty1, t => t.Ignore());
Mapper.CreateMap<Output, Input>().ForMember(s => s.InputProperty2, t => t.Ignore());
Mapper.CreateMap<Input, Output>();
listOfItems = Mapper.Map<List<Input>, List<Output>>(InputListObject);
As others suggested, we should avoid mapping lists and collections. In order to ignore all the unmapped properties, the following worked out for me.
CreateMap<Metadata, MetadataInput>()
.ForMember(dest => dest.Id, o => o.MapFrom(src => src.sourceIdentifier))
.ForMember(dest => dest.Name, o => o.MapFrom(src => src.sourceName))
.ForAllOtherMembers(opts => opts.Ignore());
ForAllOtherMembers should be the last in the method chain.
Thanks for the useful comments.
Because both lists are already made before mapping I've done it this way:
Gets the list from the db:
List<Metadata> metadatas = _Metadataservice.GetList(_Collectionservice.Get("Koekelare").ID).ToList();
Create the mapper (thanks for pointing out my mistake):
Mapper.CreateMap<Metadata, MetadataInput>().ForMember(s => s.Property, t => t.Ignore());
Make a new list and map the new (single) values one by one:
List<MetadataInput> meta = new List<MetadataInput>();
for (int i = 0; i < e.Count; i++)
{
meta.Add(Mapper.Map<Metadata, MetadataInput>(metadatas[i], input.Metadatas[i]));
}
Could someone confirm this is a good way?