Automapper's condition gets ignored

2019-06-21 07:52发布

问题:

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.

回答1:

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(...));


回答2:

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.



标签: AutoMapper