I have a scenario like
If total number of days is less than 30 days, then I have to set Salary to null
this.CreateMap<Foo, Doo>()
.ForMember(dst => dst.Salary, opt => {
opt.Condition(src => src.JoinedDate.Days <= 30));
opt.MapFrom(null)
}
But I am facing error "cannot find member of type Foo. Parameter name: name". but don't have any property "name".
Question is How to pass null value to destination property in condition check, and retain existing value if days greater than 30.
opt.MapFrom(null)
Try using:
this.CreateMap<Foo, Doo>()
.ForMember(dst => dst.Salary,
opt => opt.MapFrom(src => src.JoinedDate.Days <= 30 ? null : src.Salary))
UPD
To preserve Salary from destination use overload of MapFrom accepting both source and destination:
this.CreateMap<Foo, Doo>()
.ForMember(dst => dst.Salary,
opt => opt.MapFrom((src, dst) => src.JoinedDate.Days <= 30 ? null : dst.Salary))
You can use automapper inline ResolveUsing.
ForMember(dst => dst.Salary,
o => o.ResolveUsing(src => src.JoinedDate.Days > 30 ? src.Salary: null));
I just combined above two solutions and found answer for my question.
ForMember(dst => dst.Salary,
opt => opt.ResolveUsing((src, dst) => src.JoinedDate.Days <= 30 ? null: dst.Salary));
Related
Mapping:
.ForMember(dest => dest.DisplayName, opt =>
{
opt.PreCondition(location => location.Parent != null);
opt.MapFrom(src => src.Name + ", " + src.Parent.Name);
})
.ForMember(dest => dest.DisplayName, opt =>
{
opt.PreCondition((src, dest, context) => dest.DisplayName == null);
opt.MapFrom(src => src.Name);
})
Expected result:
If the first condition is met don't override the mapping.
What actually happens:
The second mapping is overriding the first mapping.
How can I solve this?
It doesn't work because you are overwriting previous mapping expressions calling another ForMember() for the same member, which is your case is DisplayName. Consider such case:
.ForMember(d => d.DisplayName, o => o.MapFrom(s => "1"))
.ForMember(d => d.DisplayName, o => o.MapFrom(s => "2"))
.ForMember(d => d.DisplayName, o => o.MapFrom(s => "3"));
Which value will be mapped to DisplayName?
3
So in your case, your first conditional mapping expression is overwriten by the second one. To make it work, join the conditional mapping into one mapping expression:
.ForMember(
dest => dest.DisplayName,
opts => opts.MapFrom((src, dest) =>
{
if (src.Parent != null)
{
return string.Join(", ", src.Name, src.Parent.Name);
}
else
{
if (dest.DisplayName is null)
{
return src.Name;
}
else
{
return "Some other value when no conditions were met.";
}
}
}));
It would be a cool feature to have but I don't see it anywhere in Automapper documentation.
This should however work in your case if the logic is not more complex.
.ForMember(dest => dest.DisplayName, opt =>
{
opt.MapFrom(src => src.Name + (location.Parent != null ? ", " + src.Parent.Name : null));
})
I'm fairly new to AutoMapper and want to know how to set a destination member to a value based on a DIFFERENT source property value and if that value is null I just want to apply the default behaviour of Automapper (keep destination value when the source is null)
CreateMap<ClassA, ClassA>()
.ForMember(dest => dest.PropertyA, opt =>
opt.MapFrom(src => src.PropertyB!= null ? null : opt.UseDestinationValue())
)
This doesn't work (don't compile) the opt.UseDestinationValue() , what option can I use here?
Please help
Try setting a precondition for mapping destination property.
CreateMap<ClassA, ClassA>().ForMember(dest => dest.PropertyA, opt => opt.PreCondition((src, dest) => src.PropertyB != null));
This will map PropertyA only when PropertyB is not null. I did try a quick sample which gave the desired result.
I think you can use the PreCondition option For Mapping Property
CreateMap<ClassA, ClassA>()
.ForMember(dest => dest.PropertyA, opt => {
opt.PreCondition(src => src.PropertyB!= null);
opt.MapFrom(src => src.PropertyB);
});
Hope to help you
You can do as follows:
var configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<ClassA,ClassA>()
.ForMember(dest => dest.PropertyA, opt => opt.Condition(src => (src.PropertyB!= null)));
});
Or as follows:
var configuration = new MapperConfiguration(cfg => {
cfg.CreateMap<ClassA,ClassA>()
.ForMember(dest => dest.PropertyA, opt => {
opt.PreCondition(src => (src.PropertyB!=null));
opt.MapFrom(src => src.PropertyB); // mapping process takes place here
});
});
But the difference is that, the later runs sooner in the mapping process.
There is an excellent documentation in setting conditions for automapper:
https://docs.automapper.org/en/stable/Conditional-mapping.html
Is it possible to use a custom value resolver in automapper only if a certain condition is met?
In my case I only want to update the value with the custom value resolver if the destination is not null.
This is an example of my code. Basically I need to add the condition onto this. Is it possible?
Mapper.CreateMap<ResponseXml, MyModel>()
.ForMember(dest => dest.FirstName,
op => op.ResolveUsing<ResponseXmlValueResolver>()
.FromMember(x => x.data.FirstOrDefault(y => y.name == "name")))
I think Eris' solution would have work; It was just grammatical errors.
Mapper.CreateMap<ResponseXml, MyModel>()
.ForMember(dest => dest.FirstName,
op => {
op.Condition(src => src != null);
op.ResolveUsing<ResponseXmlValueResolver>();
.FromMember(x => x.data.FirstOrDefault(y => y.name == "name"));
});
Is this what you wanted?
If the destination is null, the mapping will be ignore.
If the destination is null, the mapping (with the customer resolved) will be apply.
As Conditions are evaluated after resolving member, like it's said here, none of the previous answers are correct.
You should rather use PreCondition this way:
Mapper.CreateMap<ResponseXml, MyModel>()
.ForMember(dest => dest.FirstName,
op => {
op.PreCondition(src => src != null);
op.ResolveUsing<ResponseXmlValueResolver>();
.FromMember(x => x.data.FirstOrDefault(y => y.name == "name"));
});
Will this work? (I don't have a windows box in front of me at the moment)
Mapper.CreateMap<ResponseXml, MyModel>()
.ForMember(dest => dest.FirstName,
op => op.Condition(src => src != null)
.ResolveUsing<ResponseXmlValueResolver>()
.FromMember(x => x.data.FirstOrDefault(y => y.name == "name")))
I can't get my head round the following issue. I have a feeling it is a limitation of LINQ and expression trees, but not sure how to accept the lambda body. Can I achieve this WITHOUT creating a custom converter?
Mapper.CreateMap<I_NEWS, NewsModel>()
.ForMember(x => x.DateCreated, opt => opt.MapFrom(src => {
var dt = (DateTime)src.DateCreated;
return dt.ToShortDateString();
}));
I'm getting this error:
A lambda expression with a statement body cannot be converted to an expression tree
In order to use lambda bodies, use .ResolveUsing instead of .MapFrom.
As per the author:
MapFrom has some extra stuff that needs expression trees (like null
checking etc).
So your statement would look like this:
Mapper.CreateMap<I_NEWS, NewsModel>()
.ForMember(x => x.DateCreated, opt => opt.ResolveUsing(src => {
var dt = (DateTime)src.DateCreated;
return dt.ToShortDateString();
}));
try this:
Mapper.CreateMap<I_NEWS, NewsModel>().ForMember(x => x.DateCreated,
opt => opt.MapFrom(src => ((DateTime)src.DateCreated).ToShortDateString()));
If Nullable is destination then:
Mapper.CreateMap()
.ForMember(
dest => dest.StartDate,
opt => opt.MapFrom(
src => string.IsNullOrEmpty(src.StartDate) ? new DateTime?() : DateTime.ParseExact(src.StartDate, DATEFORMAT, CultureInfo.InvariantCulture)
)
)
I'm using automapper and I would like to know if it's possible to ignore a mapping of a field when that's null.
That's my code:
.ForMember(dest => dest.BusinessGroup_Id,
opt => opt.MapFrom(src => (int)src.BusinessGroup))
src.BusinessGroup type = "enum"
dest.BusinessGroup_Id = int
The objective it's to ingore that Mapping if src.BusinessGroup = null.
I think NullSubstitute option will do the trick
.ForMember(d => d.BusinessGroup_Id, o => o.MapFrom(s => (int?)s.BusinessGroup));
.ForMember(d => d.BusinessGroup_Id, o => o.NullSubstitute(0));
BTW you can write your conditions in mapping action:
.ForMember(d => d.BusinessGroup_Id,
o => o.MapFrom(s => s.BusinessGroup == null ? 0 : (int)s.BusinessGroup));
UPDATE if you cannot assign some default value to your property, you can just ignore it and map only not nulls:
.ForMember(d => d.BusinessGroup_Id, o => o.Ignore())
.AfterMap((s, d) =>
{
if (s.BusinessGroup != null)
d.BusinessGroup_Id = (int)s.BusinessGroup;
});