Reputation: 73112
Here's my code:
Mapper.CreateMap<Foo, Foo2>()
.ForMember(dest => dest.Bar, opt => opt.MapFrom(src => src.Bar == null ? new BarViewModel() : src.Bar))
Basically, "BarViewModel" has a parameterless ctor which sets up properties in the class.
So i'm trying to say to AutoMapper:
If the value is null, then use the ctor for the class. otherwise use the mapping you have in place
The above is giving me a C# compiler error. And i'm guessing a cast wouldn't work either.
So is there a AutoMapper trick to do this?
Worst case i could remove that mapping for that property, and just do:
var mapped = Mapper.Map<Foo,Foo2>(src);
if (mapped.Bar == null) mapped.Bar = new BarViewModel();
But that's a tad ugly.
Ideas?
Upvotes: 36
Views: 50837
Reputation: 24395
This can be done with the PreCondition()
method. Here's an extension method I wrote to do this more easily:
public static IMappingExpression<TSource, TDestination> MapIf<TSource, TDestination>(
this IMappingExpression<TSource, TDestination> map, Expression<Func<TDestination, object>> selector,
Func<TSource, bool> mapIfCondition, Expression<Func<TSource, object>> mapping)
{
map.ForMember(selector, c =>
{
c.MapFrom(mapping);
c.PreCondition(mapIfCondition);
});
return map;
}
Usage Example:
//if settings are null coming from the sender, then ignore them and keep the current settings
CreateMap<PresentationView, Presentation>()
.MapIf(x => x.Settings, x => x.Settings is not null, v => v.Settings!)
Upvotes: 5
Reputation: 15991
As of Automapper 8, ResolveUsing
is no longer an option but inline Func
's, IValueResolver
and IMemberValueResolver
are 😊.
Inline Func Example
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Foo, FooViewModel>()
.ForMember(dest => dest.BarViewModel,
opt => opt.MapFrom((src, dest) =>
{
if (src.Bar == null)
return new BarViewModel ();
return Mapper.Map<Bar, BarViewModel>(src.Bar);
}));
cfg.CreateMap<Bar, BarViewModel>();
});
IMemberValueResolver Example
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Foo, FooViewModel>()
.ForMember(dest => dest.BarViewModel,
opt => opt.MapFrom<NullBarResolver, Bar>(src => src.Bar));
cfg.CreateMap<Bar, BarViewModel>();
});
public class NullBarResolver : IMemberValueResolver<object, object, Bar, BarViewModel>
{
public BarViewModel Resolve(object source, object destination, Bar sourceMember,
BarViewModel destMember, ResolutionContext context)
{
if (sourceMember == null)
return new BarViewModel();
return Mapper.Map(sourceMember, destMember);
}
}
There's some good documentation on Custom Value Resolvers here.
Upvotes: 9
Reputation: 2509
Now you can use .NullSubstitute()
to replace NULL value to some custom value in Automapper, e.g.:
CreateMap<SMModel, VM_SMModel>()
.ForMember(d => d.myDate, o => o.NullSubstitute(new DateTime(2017,12,12)));
Upvotes: 10
Reputation: 4315
You can use custom value resolver. The following should work:
Mapper.CreateMap<Foo, Foo2>()
.ForMember(dest => dest.Bar, opt => opt.ResolveUsing(src => src.Bar == null ? new Bar() : Mapper.Map<Bar,Bar2>(src.Bar)))
Upvotes: 38
Reputation: 42354
I don't get a compiler error for the following:
public class Foo
{
public Bar Bar { get; set; }
}
public class Foo2
{
public Bar Bar { get; set; }
}
public class Bar
{
public int Id { get; set; }
public Bar()
{
Id = 3;
}
}
CreateMap<Foo, Foo2>()
.ForMember(
dest => dest.Bar,
opt => opt.MapFrom(src => src.Bar == null ? new Bar() : src.Bar));
...so I'm wondering if the problem is not actually with your mapping?
Upvotes: 3