diff --git a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs index 8ce201ce29..eddd8224b9 100644 --- a/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs +++ b/src/AutoMapper/QueryableExtensions/ProjectionBuilder.cs @@ -77,7 +77,7 @@ Expression CreateProjection(in ProjectionRequest request, LetPropertyMaps letPro { var sourceType = derivedMap.SourceType; var derivedRequest = request.InnerRequest(sourceType, derivedMap.DestinationType); - var derivedProjection = CreateProjectionCore(derivedRequest, letPropertyMaps, derivedMap, Convert(source, sourceType)); + var derivedProjection = CreateProjectionCore(derivedRequest, letPropertyMaps, derivedMap, TypeAs(source, sourceType)); projection = Condition(TypeIs(source, sourceType), derivedProjection, projection, projection.Type); } return projection; diff --git a/src/IntegrationTests/Inheritance/PolymorphismTests.cs b/src/IntegrationTests/Inheritance/PolymorphismTests.cs new file mode 100644 index 0000000000..eeb0829dbc --- /dev/null +++ b/src/IntegrationTests/Inheritance/PolymorphismTests.cs @@ -0,0 +1,104 @@ +namespace AutoMapper.IntegrationTests.Inheritance; + +public class PolymorphismTests : IntegrationTest +{ + public abstract class Vehicle + { + public int Id { get; set; } + public string Name { get; set; } + } + + public class Car : Vehicle + { + public int AmountDoors { get; set; } + } + + public class Motorcycle : Vehicle + { + public bool HasSidecar { get; set; } + } + + public class Bicycle : Vehicle + { + public bool EBike { get; set; } + } + + public class VehicleModel + { + public string Name { get; set; } + } + + public class MotorcycleModel : VehicleModel + { + public bool HasSidecar { get; set; } + } + + public class BicycleModel : VehicleModel + { + public bool EBike { get; set; } + } + + public class Context : LocalDbContext + { + public DbSet Vehicles { get; set; } + + public DbSet Cars { get; set; } + + public DbSet Motorcycles { get; set; } + + public DbSet Bicycles { get; set; } + } + + protected override MapperConfiguration CreateConfiguration() + { + return new MapperConfiguration(cfg => + { + cfg.CreateMap() + .IncludeAllDerived(); + + cfg.CreateMap(); + cfg.CreateMap(); + }); + } + + public class DatabaseInitializer : DropCreateDatabaseAlways + { + protected override void Seed(Context context) + { + context.Vehicles.Add(new Car { Name = "Car", AmountDoors = 4 }); + context.Vehicles.Add(new Bicycle { Name = "Bicycle", EBike = true }); + context.Vehicles.Add(new Motorcycle { Name = "Motorcycle", HasSidecar = true }); + + base.Seed(context); + } + } + + [Fact] + public void Should_project_base_queryable_to_derived_models_polymorphic() + { + using var context = new Context(); + var results = context.Vehicles.ProjectTo(Configuration).ToArray(); + results.Length.ShouldBe(3); + results.ShouldContain(x => x.GetType() == typeof(VehicleModel), 1); + results.ShouldContain(x => x.GetType() == typeof(BicycleModel), 1); + results.ShouldContain(x => x.GetType() == typeof(MotorcycleModel), 1); + } + + [Fact] + public void Should_project_derived_queryable_to_derived_models_if_derived_models_exist() + { + using var context = new Context(); + var results = context.Motorcycles.ProjectTo(Configuration).ToArray(); + results.Length.ShouldBe(1); + results.ShouldContain(x => x.GetType() == typeof(MotorcycleModel), 1); + } + + [Fact] + public void Should_project_derived_queryable_to_base_models_if_no_derived_models_exist() + { + using var context = new Context(); + var results = context.Cars.ProjectTo(Configuration).ToArray(); + results.Length.ShouldBe(1); + results.ShouldContain(x => x.GetType() == typeof(VehicleModel), 1); + } +} \ No newline at end of file