diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 590a25de2e..fd08dd7c41 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -54,7 +54,8 @@ private QueryExpressions CreateProjection(ProjectionRequest request) private (TypeMap, TypeMap[]) GetPolymorphicMaps(in ProjectionRequest request) { var typeMap = _configuration.ResolveTypeMap(request.SourceType, request.DestinationType) ?? throw TypeMap.MissingMapException(request.SourceType, request.DestinationType); - return (typeMap, _configuration.GetIncludedTypeMaps(typeMap.IncludedDerivedTypes.Where(tp => tp.SourceType != typeMap.SourceType).DistinctBy(tp => tp.SourceType).ToArray())); + return (typeMap, _configuration.GetIncludedTypeMaps(typeMap.IncludedDerivedTypes + .Where(tp => tp.SourceType != typeMap.SourceType && !tp.DestinationType.IsAbstract).DistinctBy(tp => tp.SourceType).ToArray())); } public QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps) { @@ -64,7 +65,9 @@ public QueryExpressions CreateProjection(in ProjectionRequest request, LetProper QueryExpressions CreateProjection(in ProjectionRequest request, LetPropertyMaps letPropertyMaps, TypeMap typeMap, TypeMap[] polymorphicMaps) { var instanceParameter = Parameter(request.SourceType, "dto" + request.SourceType.Name); - var projection = CreateProjectionCore(request, instanceParameter, typeMap, letPropertyMaps); + var destinationType = typeMap.DestinationType; + var projection = polymorphicMaps.Length > 0 && destinationType.IsAbstract ? + Default(destinationType) : CreateProjectionCore(request, instanceParameter, typeMap, letPropertyMaps); foreach(var derivedMap in polymorphicMaps) { var sourceType = derivedMap.SourceType; diff --git a/src/IntegrationTests/Inheritance/ProjectToAbstractTypeWithInheritance.cs b/src/IntegrationTests/Inheritance/ProjectToAbstractTypeWithInheritance.cs new file mode 100644 index 0000000000..4c8535a29e --- /dev/null +++ b/src/IntegrationTests/Inheritance/ProjectToAbstractTypeWithInheritance.cs @@ -0,0 +1,104 @@ +namespace AutoMapper.IntegrationTests.Inheritance; + +public class ProjectToAbstractTypeWithInheritance : IntegrationTest +{ + public class StepGroup + { + public int Id { get; set; } + public string Name { get; set; } + public virtual List Steps { get; set; } = new(); + } + public abstract class Step + { + public int Id { get; set; } + public string Name { get; set; } + public int StepGroupId { get; set; } + public virtual StepGroup StepGroup { get; set; } + } + public class CheckingStep : Step { } + public class InstructionStep : Step { } + public abstract class AbstractStep : Step { } + + public class StepGroupModel + { + public int Id { get; set; } + public string Name { get; set; } + public List Steps { get; set; } = new(); + } + public abstract class StepModel + { + public int Id { get; set; } + public string Name { get; set; } + } + public class CheckingStepModel : StepModel { } + public class InstructionStepModel : StepModel { } + public abstract class AbstractStepModel : StepModel { } + + public class Context : LocalDbContext + { + public DbSet StepGroups { get; set; } + + public DbSet Steps { get; set; } + + public DbSet CheckingSteps { get; set; } + + public DbSet InstructionSteps { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity(entity => + { + entity.HasOne(d => d.StepGroup).WithMany(p => p.Steps) + .HasForeignKey(d => d.StepGroupId); + }); + } + } + + protected override MapperConfiguration CreateConfiguration() + { + return new MapperConfiguration(cfg => + { + cfg.CreateMap(); + cfg.CreateMap(); + cfg.CreateMap() + .IncludeBase(); + cfg.CreateMap() + .IncludeBase(); + cfg.CreateMap() + .IncludeBase(); + }); + } + + public class DatabaseInitializer : DropCreateDatabaseAlways + { + protected override void Seed(Context context) + { + context.StepGroups.Add(new StepGroup + { + Name = "StepGroup", + Steps = new List + { + new InstructionStep + { + Name = "InstructionStep" + }, + new CheckingStep + { + Name = "CheckingStep" + } + } + }); + + base.Seed(context); + } + } + + [Fact] + public void ProjectCollectionWithElementInheritingAbstractClass() + { + using var context = new Context(); + var steps = ProjectTo(context.StepGroups).Single().Steps; + steps[0].ShouldBeOfType().Name.ShouldBe("CheckingStep"); + steps[1].ShouldBeOfType().Name.ShouldBe("InstructionStep"); + } +} \ No newline at end of file