Карта AutoMapper, если не нуль, в противном случае пользовательский конвертировать
Здесь мой код:
Mapper.CreateMap<Foo, Foo2>()
.ForMember(dest => dest.Bar, opt => opt.MapFrom(src => src.Bar == null ? new BarViewModel() : src.Bar))
В принципе, "BarViewModel" имеет без параметров ctor, который устанавливает свойства в классе.
Итак, я пытаюсь сказать AutoMapper:
Если значение равно null, используйте ctor для класса. в противном случае используйте сопоставление, которое у вас есть.
Вышеупомянутое дает мне ошибку компилятора С#. И я предполагаю, что актер тоже не будет работать.
Итак, есть ли трюк AutoMapper?
В худшем случае я мог удалить это сопоставление для этого свойства и просто сделать:
var mapped = Mapper.Map<Foo,Foo2>(src);
if (mapped.Bar == null) mapped.Bar = new BarViewModel();
Но это немного уродливое.
Идеи?
Ответы
Ответ 1
Вы можете использовать настраиваемый преобразователь значений. Должно работать следующее:
Mapper.CreateMap<Foo, Foo2>()
.ForMember(dest => dest.Bar, opt => opt.ResolveUsing(src => src.Bar == null ? new Bar() : Mapper.Map<Bar,Bar2>(src.Bar)))
Ответ 2
Теперь вы можете использовать .NullSubstitute()
для замены значения NULL для некоторого настраиваемого значения в Automapper, например:
CreateMap<SMModel, VM_SMModel>()
.ForMember(d => d.myDate, o => o.NullSubstitute(new DateTime(2017,12,12)));
Ответ 3
Я не получаю ошибку компилятора для следующего:
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));
... так что мне интересно, не проблема ли на самом деле с вашим отображением?
Ответ 4
Начиная с Automapper 8, ResolveUsing
больше не является опцией, а встроенные Func
, IValueResolver
и IMemberValueResolver
равны 😊.
Пример встроенного функционала
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
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);
}
}
Здесь есть хорошая документация по Решателям пользовательских значений.
Рабочая демонстрация