Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/Mapping-inheritance.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ CreateMap<DerivedEntity, DerivedDto>()

In each case above, the derived mapping inherits the custom mapping configuration from the base mapping configuration.

To include all derived maps, from the base type map configuration:

```c#
CreateMap<BaseEntity, BaseDto>()
.IncludeAllDerived();

CreateMap<DerivedEntity, DerivedDto>();
```

### Runtime polymorphism

Take:
Expand Down
8 changes: 8 additions & 0 deletions src/AutoMapper/Configuration/MappingExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ public IMappingExpression ForMember(string name, Action<IMemberConfigurationExpr

public new IMappingExpression PreserveReferences() => (IMappingExpression)base.PreserveReferences();

public new IMappingExpression IncludeAllDerived() => (IMappingExpression) base.IncludeAllDerived();

protected override IPropertyMapConfiguration CreateMemberConfigurationExpression<TMember>(MemberInfo member, Type sourceType)
=> new MemberConfigurationExpression(member, sourceType);

Expand Down Expand Up @@ -532,6 +534,12 @@ public IMappingExpression<TSource, TDestination> ValidateMemberList(MemberList m
});
return this;
}

public IMappingExpression<TSource, TDestination> IncludeAllDerived()
{
TypeMapActions.Add(tm => tm.IncludeAllDerivedTypes = true);
return this;
}

private IPropertyMapConfiguration GetDestinationMemberConfiguration(MemberInfo destinationMember) =>
_memberConfigurations.FirstOrDefault(m => m.DestinationMember == destinationMember);
Expand Down
11 changes: 11 additions & 0 deletions src/AutoMapper/IMappingExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ IMappingExpression AfterMap<TMappingAction>()
/// <param name="memberList">Member list to validate</param>
/// <returns>Itself</returns>
IMappingExpression ValidateMemberList(MemberList memberList);

/// <summary>
/// Include this configuration in all derived types' maps
/// </summary>
/// <returns>Itself</returns>
IMappingExpression IncludeAllDerived();
}

/// <summary>
Expand Down Expand Up @@ -444,5 +450,10 @@ IMappingExpression<TSource, TDestination> ForSourceMember(string sourceMemberNam
/// <returns>Itself</returns>
IMappingExpression<TSource, TDestination> ValidateMemberList(MemberList memberList);

/// <summary>
/// Include this configuration in all derived types' maps
/// </summary>
/// <returns>Itself</returns>
IMappingExpression<TSource, TDestination> IncludeAllDerived();
}
}
13 changes: 13 additions & 0 deletions src/AutoMapper/MapperConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,19 @@ private void Seal()
profile.Register(this);
}

foreach (var typeMap in _typeMapRegistry.Values.Where(tm => tm.IncludeAllDerivedTypes))
{
foreach (var derivedMap in _typeMapRegistry
.Where(tm =>
typeMap.SourceType.IsAssignableFrom(tm.Key.SourceType) &&
typeMap.DestinationType.IsAssignableFrom(tm.Key.DestinationType) &&
typeMap != tm.Value)
.Select(tm => tm.Value))
{
typeMap.IncludeDerivedTypes(derivedMap.SourceType, derivedMap.DestinationType);
}
}

foreach (var profile in Profiles)
{
profile.Configure(this);
Expand Down
2 changes: 2 additions & 0 deletions src/AutoMapper/TypeMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public PathMap FindPathMapByDestinationPath(string destinationFullPath) =>

public bool ConstructDestinationUsingServiceLocator { get; set; }

public bool IncludeAllDerivedTypes { get; set; }

public MemberList ConfiguredMemberList { get; set; }

public IEnumerable<TypePair> IncludedDerivedTypes => _includedDerivedTypes;
Expand Down
45 changes: 45 additions & 0 deletions src/UnitTests/MappingInheritance/IncludeAllDerived.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Shouldly;
using Xunit;

namespace AutoMapper.UnitTests.MappingInheritance
{
public class IncludeAllDerived : AutoMapperSpecBase
{
public class A
{
public int Value { get; set; }
}
public class B : A { }
public class C : B { }
public class D : A { }

public class ADto
{
public int Value { get; set; }
}

public class BDto : ADto { }
public class CDto : BDto { }
public class DDto : ADto { }

protected override MapperConfiguration Configuration { get; } = new MapperConfiguration(cfg =>
{
cfg.CreateMap<A, ADto>()
.ForMember(d => d.Value, opt => opt.MapFrom(src => 5))
.IncludeAllDerived();

cfg.CreateMap<B, BDto>();
cfg.CreateMap<C, CDto>();
cfg.CreateMap<D, DDto>();
});

[Fact]
public void Should_apply_configuration_to_all_derived()
{
Mapper.Map<ADto>(new A {Value = 10}).Value.ShouldBe(5);
Mapper.Map<BDto>(new B {Value = 10}).Value.ShouldBe(5);
Mapper.Map<CDto>(new C {Value = 10}).Value.ShouldBe(5);
Mapper.Map<DDto>(new D {Value = 10}).Value.ShouldBe(5);
}
}
}