diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs index 177619b34d..f76ddad634 100644 --- a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs @@ -1,5 +1,5 @@ -using System; using Microsoft.Extensions.DependencyInjection; +using System; using Volo.Abp.DependencyInjection; namespace Volo.Abp.ObjectMapping @@ -22,7 +22,6 @@ namespace Volo.Abp.ObjectMapping return default; } - //Check if a specific mapper is registered using (var scope = _serviceProvider.CreateScope()) { var specificMapper = scope.ServiceProvider.GetService>(); @@ -32,6 +31,26 @@ namespace Volo.Abp.ObjectMapping } } + if (source is IMapTo mapperSource) + { + return mapperSource.MapTo(); + } + + if (typeof(IMapFrom).IsAssignableFrom(typeof(TDestination))) + { + try + { + //TODO: Check if TDestination has a proper constructor which takes TSource + //TODO: Check if TDestination has an empty constructor (in this case, use MapFrom) + + return (TDestination) Activator.CreateInstance(typeof(TDestination), source); + } + catch + { + //TODO: Remove catch when TODOs are implemented above + } + } + return AutoMap(source); } @@ -42,7 +61,6 @@ namespace Volo.Abp.ObjectMapping return default; } - //Check if a specific mapper is registered using (var scope = _serviceProvider.CreateScope()) { var specificMapper = scope.ServiceProvider.GetService>(); @@ -52,6 +70,18 @@ namespace Volo.Abp.ObjectMapping } } + if (source is IMapTo mapperSource) + { + mapperSource.MapTo(destination); + return destination; + } + + if (destination is IMapFrom mapperDestination) + { + mapperDestination.MapFrom(source); + return destination; + } + return AutoMap(source, destination); } diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/IMapFrom.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/IMapFrom.cs new file mode 100644 index 0000000000..7da41657f8 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/IMapFrom.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.ObjectMapping +{ + public interface IMapFrom + { + void MapFrom(TSource source); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/IMapTo.cs b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/IMapTo.cs new file mode 100644 index 0000000000..2db5ea00bc --- /dev/null +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/IMapTo.cs @@ -0,0 +1,9 @@ +namespace Volo.Abp.ObjectMapping +{ + public interface IMapTo + { + TDestination MapTo(); + + void MapTo(TDestination destination); + } +} diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs index c647abb57c..cfc846f3b7 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.AutoMapper.SampleClasses; @@ -21,5 +22,43 @@ namespace Volo.Abp.AutoMapper var dto = _objectMapper.Map(new MyEntity { Number = 42 }); dto.Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. } + + [Fact] + public void Should_Use_Destination_Object_Constructor_If_Available() + { + var id = Guid.NewGuid(); + var dto = _objectMapper.Map(new MyEntity { Number = 42, Id = id}); + dto.Key.ShouldBe(id); + dto.No.ShouldBe(42); + } + + [Fact] + public void Should_Use_Destination_Object_MapFrom_Method_If_Available() + { + var id = Guid.NewGuid(); + var dto = new MyEntityDtoWithMappingMethods(); + _objectMapper.Map(new MyEntity { Number = 42, Id = id }, dto); + dto.Key.ShouldBe(id); + dto.No.ShouldBe(42); + } + + [Fact] + public void Should_Use_Source_Object_Method_If_Available_To_Create_New_Object() + { + var id = Guid.NewGuid(); + var entity = _objectMapper.Map(new MyEntityDtoWithMappingMethods{Key = id, No = 42}); + entity.Id.ShouldBe(id); + entity.Number.ShouldBe(42); + } + + [Fact] + public void Should_Use_Source_Object_Method_If_Available_To_Map_Existing_Object() + { + var id = Guid.NewGuid(); + var entity = new MyEntity(); + _objectMapper.Map(new MyEntityDtoWithMappingMethods { Key = id, No = 42 }, entity); + entity.Id.ShouldBe(id); + entity.Number.ShouldBe(42); + } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyEntityDtoWithMappingMethods.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyEntityDtoWithMappingMethods.cs new file mode 100644 index 0000000000..5366ae25d2 --- /dev/null +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyEntityDtoWithMappingMethods.cs @@ -0,0 +1,44 @@ +using System; +using Volo.Abp.ObjectMapping; + +namespace Volo.Abp.AutoMapper.SampleClasses +{ + //TODO: Move tests to Volo.Abp.ObjectMapping test project + public class MyEntityDtoWithMappingMethods : IMapFrom, IMapTo + { + public Guid Key { get; set; } + + public int No { get; set; } + + public MyEntityDtoWithMappingMethods() + { + + } + + public MyEntityDtoWithMappingMethods(MyEntity entity) + { + MapFrom(entity); + } + + public void MapFrom(MyEntity source) + { + Key = source.Id; + No = source.Number; + } + + MyEntity IMapTo.MapTo() + { + return new MyEntity + { + Id = Key, + Number = No + }; + } + + void IMapTo.MapTo(MyEntity destination) + { + destination.Id = Key; + destination.Number = No; + } + } +} \ No newline at end of file