So my code appears as:
CreateMap<EntityOne, ModelOne>()
.ForPath(dest => dest.Field1, opt => opt.MapFrom(src => src.Field1))
Both Field1 are nullable decimals, I want to be able to convert the value to 2 decimal places as I'm mapping. Think my best attempt has been:
CreateMap<EntityOne, ModelOne>()
.ForPath(dest => dest.Field1, opt => opt.MapFrom(src => src.Field1.HasValue ? Math.Round((decimal)src.Field1, 2, MidpointRounding.AwayFromZero) : null))
The error I get is:
The type arguments for method 'IPathConfigurationExpression<EntityOne, ModelOne, decimal?>.MapFrom(Expression<Func<EntityOne, TSourceMember>>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
I'm pretty sure you can solve this by just casting the result of Math.Round to a nullable decimal:
opt.MapFrom(src => src.Field1.HasValue
? (decimal?)Math.Round((decimal)src.Field1, 2, MidpointRounding.AwayFromZero)
: null)
This way the call should be able to be "inferred from the usage"
Related
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));
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
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)
)
)
This question already has answers here:
AutoMapper: "Ignore the rest"?
(20 answers)
Closed 6 years ago.
Is there a way to do this? We have a SummaryDto that maps from three different types, and when we create a map for each type, props that are not mapped are throwing an error. There are about 35 attributes on the summary dto. To use Ignore() option on each one is just too much trouble. Is there a global ignore? Something like
CreateMap<Source,Target>()
.IgnoreAllUnmapped();
This is working for me:
public static class MappingExpressionExtensions
{
public static IMappingExpression<TSource, TDest> IgnoreAllUnmapped<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
{
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
}
Because ForAllMembers returns void, calling ForAllMembers(o => o.Ignore()) without this extension method wouldn't work. We want to keep the mapping expression available to enable the subsequent mappings:
CreateMap<Source, Destination>()
.IgnoreAllUnmapped()
.ForMember(d => d.Text, o => o.MapFrom(s => s.Name))
.ForMember(d => d.Value, o => o.MapFrom(s => s.Id));
I struggled with this one for quite a while too, or at least a problem similar to this. I had a class with a lot of properties on it (about 30) and I only wanted to map about 4 of them. It seems crazy to add 26 ignore statements (especially when it means that future changes to the class will mean having to update them!)
I finally found that I could tell AutoMapper to ignore everything, and then explicitly add the ones that I did want.
// Create a map, store a reference to it in a local variable
var map = CreateMap<Source,Target>();
// Ignore all members
map.ForAllMembers(opt => opt.Ignore());
// Add mapping for P1
map.ForMember(dest => dest.P1, opt => opt.MapFrom( src => src.P1));
// Add other mappings...
map.ForMember(dest => dest.P2, opt => opt.MapFrom( src => src.P2));
map.ForMember(dest => dest.P3, opt => opt.MapFrom( src => src.P3));
map.ForMember(dest => dest.P4, opt => opt.MapFrom( src => src.P4));
You'd be forgiven for thinking that you could just do this (but don't because it wont compile):
// This won't compile
CreateMap<Source,Target>()
.ForAllMembers(opt => opt.Ignore())
.ForMember(dest => dest.P1, opt => opt.MapFrom( src => src.P1));
The reason why this doesn't work is that the ForAllMembers() method doesn't support the fluent style of chaining (at least in the current version 2.0).
The good news is that the non-chaining version does indeed work. The one caveat of course is that you need to explicitly tell AutoMapper which members to map. I haven't yet found an easy way to have it both ways so that you can still use the implied mappings and ignore the broken ones.
To avoid having to explicitly specify the mapped properties, you can use IgnoreAllNonExisting. It ignores any destination properties that don't have mapped source properties.
Try to use .ConvertUsing() in your case, e.g.
CreateMap<Source,Target>()
.ConvertUsing(converter=> new Target(){
P1 = converter.P1,
....
});
So, you can describe all properties what you want to have in your object, other will be ignored.
Extension method which allows fluent syntax for the ForAllMembers method:
public static IMappingExpression<TSource, TDestination> IgnoreAllMembers<TSource, TDestination>(
this IMappingExpression<TSource, TDestination> expression
)
{
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
Usage:
The call to IgnoreAllMembers must be before the call to ForMember.
CreateMap<LocationRevision, Dto.LocationAddressMap>()
.IgnoreAllMembers()
.ForMember(m => m.LocationId, opt => opt.MapFrom(src => src.Id))
;
With the following mapping:
Mapper.CreateMap<ObjectA, ObjectB>()
.ForMember(dest => dest.SomeStringProperty, opt => opt.MapFrom(src => null))
SomeStringProperty is now empty string not null (as I would expect)
Is this a bug? How can I get it to actually be null?
I see that opt.Ignore() will make it null but I actually want to do a conditional null like the following and the above simplified bug(?) is preventing this
Mapper.CreateMap<ObjectA, ObjectB>()
.ForMember(dest => dest.SomeStringProperty, opt => opt.MapFrom(src => src.SomeOtherProp != null ? src.SomeOtherProp.Prop1 : null))
I found the setting after looking through the source code... Confirming that this is not a bug, but in fact a configurable setting.
When I configure my mappings..
Mapper.Initialize(x =>
{
x.AddProfile<UIProfile>();
x.AddProfile<InfrastructureProfile>();
x.AllowNullDestinationValues = true; // does exactly what it says (false by default)
});
you could define map for strings using
ITypeConverter<string, string>
and when you convert return null if null. I think it is by design that you get an empty string and I even find this natural and useful myself but I may of course be wrong ;)
I can provide more precise code than above upon request but reckon you know what you're doing.