Issue Seems like the condition gets ignored. Here is my scenario:
Source class
public class Source
{
public IEnumerable<Enum1> Prop1{ get; set; }
public IEnumerable<Enum2> Prop2{ get; set; }
public IEnumerable<Enum3> Prop3{ get; set; }
}
The enums subclass from a byte and are decorated with [Flags]. The destination class simply contains properties like Enum1, Enum2 and Enum3 containging the "total" bitwise value. So in essense if the Enumeration contains Enum1.value!, Enum1.Value2 and Enum1.Value3, the destination will contain the bitwise value of Enum1.Value1 | Enum1.Value2 | Enum1.Value3
Destination class
public Enum1 Prop1 { get; set; }
public Enum2 Prop2 { get; set; }
public Enum3 Prop3 { get; set; }
AutoMapper Mapping
Mapper.CreateMap<Source, Destination>()
.ForMember(m => m.Prop1, o =>
{
o.Condition(c => !c.IsSourceValueNull);
o.MapFrom(f => f.Prop1.Aggregate((current, next) => current | next));
})
.ForMember(m => m.Prop2, o =>
{
o.Condition(c => !c.IsSourceValueNull);
o.MapFrom(f => f.Prop2.Aggregate((current, next) => current | next));
})
.ForMember(m => m.Prop3, o =>
{
o.Condition(c => !c.IsSourceValueNull);
o.MapFrom(f => f.Prop3.Aggregate((current, next) => current | next));
});
The mapping works fine when the inner properties are not null and mapping succeeds and sets destination correctly. However, I want to skip the mapping when the member source value is null (when Prop1 is null, then skip the mapping).
I can see from debugging that Source.Prop1 is null. The condition gets completely ignored and get the exception saying the value is null.
Trying to map Source to Destination. Destination property: Prop1. Exception of type 'AutoMapper.AutoMapperMappingException' was thrown. --> Value cannot be null. Parameter name: source
I'm not sure if IsSourceValueNull checking for Prop1 or the the actual Source class which is not null. Only the member Prop1 is null.
Any help isappreciated.
If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.
So, the AutoMapper Ignore() method is used when you want to completely ignore the property in the mapping. The ignored property could be in either the source or the destination object.
I've found ValueInjecter the best out of the automapper, emitmapper, and a few others on codeplex. I choose ValueInjector because it's the most flexible of them all.
The Null substitution allows us to supply an alternate value for a destination member if the source value is null. That means instead of mapping the null value from the source object, it will map from the value we supply.
I think you need to do the Condition
and MapFrom
in two steps:
.ForMember(c => c.Prop1, o => o.Condition(c => !c.IsSourceValueNull));
.ForMember(c => c.Prop1, o => o.MapFrom(f => f.Prop1.Aggregate(...));
The MapFrom will never be used if the Condition evaluates to false.
EDIT
Hmmm... That doesn't seem to work. I thought I had used that before somewhere. You could resort to just the MapFrom:
.MapFrom(f => f.Prop1 == null ? null : f.Prop1.Aggregate(...));
IMO, this is actually a bug in AutoMapper's EnumMapper. The condition statements, as you have them above, should work fine. For example, when mapping from one concrete type to another the TypeMapMapper will correctly call the conditional:
object mappedObject = !context.TypeMap.ShouldAssignValue(context) ? null : mapperToUse.Map(context, mapper);
Which eventually calls the defined condition:
public bool ShouldAssignValue(ResolutionContext context)
{
return _condition == null || _condition(context);
}
But the EnumMapper
doesn't call the TypeMap's ShouldAssignValue
method to find out if it should indeed map that field. Similarly, I don't see any reference to AfterMap
so it's unlikely that anything defined there is not going to work as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With