From e70a0ac86a10bfd0dc8bf5df3f0cb6422cfea0e5 Mon Sep 17 00:00:00 2001 From: maliming Date: Wed, 16 Aug 2023 20:29:15 +0800 Subject: [PATCH] Clear destination collection. --- .../Abp/ObjectMapping/DefaultObjectMapper.cs | 16 +++- ...apperModule_Specific_ObjectMapper_Tests.cs | 79 ++++++++++++++++--- 2 files changed, 83 insertions(+), 12 deletions(-) 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 21a001266a..4286672a7e 100644 --- a/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs +++ b/framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs @@ -149,6 +149,12 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency ? Activator.CreateInstance(definitionGenericType.MakeGenericType(destinationArgumentType))!.As() : Array.CreateInstance(destinationArgumentType, sourceList.Count); + if (destination != null && !destination.GetType().IsArray) + { + //Clear destination collection if destination not an array, We won't change array just same behavior as AutoMapper. + destination.As().Clear(); + } + for (var i = 0; i < sourceList.Count; i++) { var invokeResult = destination == null @@ -158,6 +164,7 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency if (definitionGenericType.IsGenericType) { result.Add(invokeResult); + destination?.As().Add(invokeResult); } else { @@ -165,7 +172,14 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency } } - return (TDestination)result!; + if (destination != null && destination.GetType().IsArray) + { + //Return the new collection if destination is an array, We won't change array just same behavior as AutoMapper. + return (TDestination)result; + } + + //Return the destination if destination exists. The parameter reference equals with return object. + return destination ?? (TDestination)result; } protected virtual bool IsCollectionGenericType(out Type sourceArgumentType, out Type destinationArgumentType, out Type definitionGenericType) 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 9eb537cec5..46f028596d 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 @@ -30,47 +30,104 @@ public class AbpAutoMapperModule_Specific_ObjectMapper_Tests : AbpIntegratedTest [Fact] public void Specific_Object_Mapper_Should_Be_Used_For_Collections_If_Registered() { + // IEnumerable _objectMapper.Map, IEnumerable>(new List() { new MyEntity { Number = 42 } }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + var destination = new List() + { + new MyEntityDto2 { Number = 44 } + }; + var returnIEnumerable = _objectMapper.Map, IEnumerable>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnIEnumerable.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnIEnumerable).ShouldBeTrue(); + + // ICollection _objectMapper.Map, ICollection>(new List() { new MyEntity { Number = 42 } }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + var returnICollection = _objectMapper.Map, ICollection>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnICollection.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnICollection).ShouldBeTrue(); + + // Collection _objectMapper.Map, Collection>(new Collection() { new MyEntity { Number = 42 } - }, new Collection() //When mapping to an existing collection, the destination collection is cleared first + }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var destination2 = new Collection() { new MyEntityDto2 { Number = 44 } - }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + }; + var returnCollection = _objectMapper.Map, Collection>( + new Collection() + { + new MyEntity { Number = 42 } + }, destination2); + returnCollection.First().Number.ShouldBe(43); + ReferenceEquals(destination2, returnCollection).ShouldBeTrue(); + // IList _objectMapper.Map, IList>(new List() { new MyEntity { Number = 42 } - }, new Collection() //When mapping to an existing collection, the destination collection is cleared first - { - new MyEntityDto2 { Number = 44 } }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + var returnIList = _objectMapper.Map, IList>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnIList.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnIList).ShouldBeTrue(); + + // List _objectMapper.Map, List>(new List() { new MyEntity { Number = 42 } - }, new List() //When mapping to an existing collection, the destination collection is cleared first - { - new MyEntityDto2 { Number = 44 } }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + var returnList = _objectMapper.Map, List>( + new List() + { + new MyEntity { Number = 42 } + }, destination); + returnList.First().Number.ShouldBe(43); + ReferenceEquals(destination, returnList).ShouldBeTrue(); + + // Array _objectMapper.Map(new MyEntity[] { new MyEntity { Number = 42 } - }, new MyEntityDto2[] //When mapping to an existing collection, the destination collection is cleared first - { - new MyEntityDto2 { Number = 44 } }).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source. + + var destinationArray = new MyEntityDto2[] + { + new MyEntityDto2 { Number = 40 } + }; + var returnArray = _objectMapper.Map(new MyEntity[] + { + new MyEntity { Number = 42 } + }, destinationArray); + + returnArray.First().Number.ShouldBe(43); + + // array should not be changed. Same as AutoMapper. + destinationArray.First().Number.ShouldBe(40); + ReferenceEquals(returnArray, destinationArray).ShouldBeFalse(); } [Fact]