When using Internal().AllowAdditiveTypeMapCreation = true;
, I was expecting that
CreateMap<Source, Destination>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
CreateMap<Source, Destination>()
.ForMember(dest => dest.Name, opt => opt.Ignore());
would be merged/combined to
CreateMap<Source, Destination>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.Name, opt => opt.Ignore());
However, it doesn't seem to be the case. The last CreateMap()
was given priority and during test, it's complaining that dest.Id
wasn't mapped. It's still throwing the same exception even if I place both CreateMap()
in different Profiles.
You can find its fiddle here https://dotnetfiddle.net/FEu6Td
Is my understanding of AllowAdditiveTypeMapCreation
incorrect? There isn't any documentation on it. I'm only able to find a brief description from the source code
Allow the same map to exist in different profiles. The default is to throw an exception, true means the maps are merged.
Use Case
A little detail about what I'm trying to achieve. Assuming I have a handful of Source/Destination pairs with a common property that I would like to ignore
public class Source1 { public DateTime CreationDate { get; set; } }
public class Destination1 { public DateTime CreationDate { get; set; } }
public class Source2 { public DateTime CreationDate { get; set; } }
public class Destination2 { public DateTime CreationDate { get; set; } }
public class Source3 { public DateTime CreationDate { get; set; } }
public class Destination3 {
public DateTime CreationDate { get; set; }
public string ExtraProperty { get; set; } // an additional property that I would want to ignore later.
}
These Source/Destination pairs can be marked with an interface or System.Attribute
and retrieved using reflection into an array. Let's pretend the array below is obtained using some other means.
var listSourceDestination = new[]
{
new KeyValuePair<Type, Type>(typeof(Source1), typeof(Destination1)),
new KeyValuePair<Type, Type>(typeof(Source2), typeof(Destination2)),
new KeyValuePair<Type, Type>(typeof(Source3), typeof(Destination3))
}
I can then loop through each pair and use the non-generic CreateMap()
to ignore the common property.
foreach (var pair in listSourceDestination)
{
CreateMap(pair.Key, pair.Value)
.ForMember("CreationDate", opt => opt.Ignore());
}
After that I would like to ignore the ExtraProperty
of Destination3
. Since I know the type, I can use the generic CreateMap<,>()
.
CreateMap<Source3, Destination3>()
.ForMember(dest => dest.ExtraProperty, opt => opt.Ignore());
Since the mapping of the pair Source3/Destination3 was created twice: once using the non-generic CreateMap()
inside a loop and the other using the generic CreateMap<,>()
. I was hoping that both CreateMap()
would merge the mapping into something like
CreateMap<Source3, Destination3>()
.ForMember(dest => dest.CreationDate, opt => opt.Ignore())
.ForMember(dest => dest.ExtraProperty, opt => opt.Ignore());
Mapping Inheritance
@Lucian Bargaoanu mentioned the use of mapping inheritance, so I'd explore the idea here with the above example. I created a base Source/Destination pair which would be inherited by the rest of the pairs.
public abstract class BaseSource { public DateTime CreationDate { get; set; } }
public abstract class BaseDestination { public DateTime CreationDate { get; set; } }
public class Source1 : BaseSource {}
public class Destination1 : BaseDestination {}
public class Source2 : BaseSource {}
public class Destination2 : BaseDestination {}
public class Source3 : BaseSource {}
public class Destination3 : BaseDestination { public string ExtraProperty { get; set; } }
Then we have the same list of source/destination pairs from above
var listSourceDestination = new[]
{
new KeyValuePair<Type, Type>(typeof(Source1), typeof(Destination1)),
new KeyValuePair<Type, Type>(typeof(Source2), typeof(Destination2)),
new KeyValuePair<Type, Type>(typeof(Source3), typeof(Destination3))
}
Now we create a map for the base pair first.
CreateMap<BaseSource, BaseDestination>()
.ForMember(dest => dest.CreationDate, opt => opt.Ignore());
// we could also use the non-generic version
CreateMap(typeof(BaseSource), typeof(BaseDestination))
.ForMember("CreationDate", opt => opt.Ignore());
Next, we loop through the list of derived source/destination pairs and inherit from the base map.
foreach (var pair in listSourceDestination)
{
CreateMap(pair.Key, pair.Value)
.IncludeBase(typeof(BaseSource), typeof(BaseDestination)); // we still need this line to indicate that we want to inherit from the base map.
}
And finally we still need the same map to ignore the ExtraProperty
from Destination3
.
CreateMap<Source3, Destination3>()
//.IncludeBase(typeof(BaseSource), typeof(BaseDestination)) // I shouldn't be needing this line here because I'm expecting the loop above to already included it. If I still needed this line, then this map essentially overriden/replaced the one in the loop above and the whole `AllowAdditiveTypeMapCreation = true` isn't what I think it is anymore (which is to merge mappings and not overriding it - last one wins).
.ForMember(dest => dest.ExtraProperty, opt => opt.Ignore());