diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index e277fbf202..ab07f6235e 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -7,7 +7,8 @@ namespace AutoMapper public static class AbpAutoMapperExtensibleDtoExtensions { public static IMappingExpression MapExtraProperties( - this IMappingExpression mappingExpression) + this IMappingExpression mappingExpression, + MappingPropertyDefinitionCheck definitionCheck = MappingPropertyDefinitionCheck.Both) where TDestination : IHasExtraProperties where TSource : IHasExtraProperties { @@ -15,28 +16,21 @@ namespace AutoMapper .ForMember( x => x.ExtraProperties, y => y.MapFrom( - (source, dto, extraProps) => + (source, destination, extraProps) => { var result = extraProps.IsNullOrEmpty() ? new Dictionary() : new Dictionary(extraProps); - var objectExtension = ObjectExtensionManager.Instance.GetOrNull(); - - if (objectExtension != null) - { - foreach (var property in objectExtension.GetProperties()) - { - if (source.ExtraProperties.ContainsKey(property.Name)) - { - result[property.Name] = source.ExtraProperties[property.Name]; - } - } - } + HasExtraPropertiesObjectExtendingExtensions + .MapExtraPropertiesTo( + source.ExtraProperties, + result + ); return result; }) ); } } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs index 92dfeb8d19..61ee13fc89 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending @@ -12,8 +13,8 @@ namespace Volo.Abp.ObjectExtending /// Checks property definitions (over the ) /// based on the preference. /// - /// - /// + /// Source class type + /// Destination class type /// The source object /// The destination object /// @@ -25,6 +26,34 @@ namespace Volo.Abp.ObjectExtending MappingPropertyDefinitionCheck definitionCheck = MappingPropertyDefinitionCheck.Both) where TSource : IHasExtraProperties where TDestination : IHasExtraProperties + { + MapExtraPropertiesTo( + source.ExtraProperties, + destination.ExtraProperties, + definitionCheck + ); + } + + /// + /// Copies extra properties from the object + /// to the object. + /// + /// Checks property definitions (over the ) + /// based on the preference. + /// + /// Source class type (for definition check) + /// Destination class type (for definition check) + /// The source dictionary object + /// The destination dictionary object + /// + /// Controls which properties to map. + /// + public static void MapExtraPropertiesTo( + Dictionary sourceDictionary, + Dictionary destinationDictionary, + MappingPropertyDefinitionCheck definitionCheck = MappingPropertyDefinitionCheck.Both) + where TSource : IHasExtraProperties + where TDestination : IHasExtraProperties { var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); if (definitionCheck.HasFlag(MappingPropertyDefinitionCheck.Source) && @@ -42,40 +71,40 @@ namespace Volo.Abp.ObjectExtending if (definitionCheck == MappingPropertyDefinitionCheck.None) { - foreach (var keyValue in source.ExtraProperties) + foreach (var keyValue in sourceDictionary) { - destination.ExtraProperties[keyValue.Key] = keyValue.Value; + destinationDictionary[keyValue.Key] = keyValue.Value; } } else if (definitionCheck == MappingPropertyDefinitionCheck.Source) { foreach (var property in sourceObjectExtension.GetProperties()) { - if (!source.ExtraProperties.ContainsKey(property.Name)) + if (!sourceDictionary.ContainsKey(property.Name)) { continue; } - destination.ExtraProperties[property.Name] = source.ExtraProperties[property.Name]; + destinationDictionary[property.Name] = sourceDictionary[property.Name]; } } else if (definitionCheck == MappingPropertyDefinitionCheck.Destination) { - foreach (var keyValue in source.ExtraProperties) + foreach (var keyValue in sourceDictionary) { if (!destinationObjectExtension.HasProperty(keyValue.Key)) { continue; } - destination.ExtraProperties[keyValue.Key] = keyValue.Value; + destinationDictionary[keyValue.Key] = keyValue.Value; } } - else if(definitionCheck == MappingPropertyDefinitionCheck.Both) + else if (definitionCheck == MappingPropertyDefinitionCheck.Both) { foreach (var property in sourceObjectExtension.GetProperties()) { - if (!source.ExtraProperties.ContainsKey(property.Name)) + if (!sourceDictionary.ContainsKey(property.Name)) { continue; } @@ -85,7 +114,7 @@ namespace Volo.Abp.ObjectExtending continue; } - destination.ExtraProperties[property.Name] = source.ExtraProperties[property.Name]; + destinationDictionary[property.Name] = sourceDictionary[property.Name]; } } else diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/AutoMapper/AbpAutoMapperExtensibleDtoExtensions_Tests.cs b/framework/test/Volo.Abp.AutoMapper.Tests/AutoMapper/AbpAutoMapperExtensibleDtoExtensions_Tests.cs new file mode 100644 index 0000000000..a55e7d32e3 --- /dev/null +++ b/framework/test/Volo.Abp.AutoMapper.Tests/AutoMapper/AbpAutoMapperExtensibleDtoExtensions_Tests.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.AutoMapper; +using Volo.Abp.Data; +using Volo.Abp.ObjectExtending.TestObjects; +using Volo.Abp.Testing; +using Xunit; + +namespace AutoMapper +{ + public class AbpAutoMapperExtensibleDtoExtensions_Tests : AbpIntegratedTest + { + private readonly Volo.Abp.ObjectMapping.IObjectMapper _objectMapper; + + public AbpAutoMapperExtensibleDtoExtensions_Tests() + { + _objectMapper = ServiceProvider.GetRequiredService(); + } + + [Fact] + public void MapExtraPropertiesTo_Should_Only_Map_Defined_Properties_By_Default() + { + var person = new ExtensibleTestPerson() + .SetProperty("Name", "John") + .SetProperty("Age", 42) + .SetProperty("ChildCount", 2) + .SetProperty("Sex", "male"); + + var personDto = new ExtensibleTestPersonDto() + .SetProperty("ExistingDtoProperty", "existing-value"); + + _objectMapper.Map(person, personDto); + + personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes + personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination + personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source + personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + personDto.GetProperty("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values + } + } +} diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj b/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj index acdd6fac6b..6178700db1 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo.Abp.AutoMapper.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperTestModule.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperTestModule.cs index 3d873ccacf..44331522a7 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperTestModule.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AutoMapperTestModule.cs @@ -1,9 +1,12 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Modularity; +using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.AutoMapper { - [DependsOn(typeof(AbpAutoMapperModule))] + [DependsOn( + typeof(AbpAutoMapperModule), + typeof(AbpObjectExtendingTestModule) + )] public class AutoMapperTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyMapProfile.cs b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyMapProfile.cs index a65a7209e2..7fb8dbd2fa 100644 --- a/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyMapProfile.cs +++ b/framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyMapProfile.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Volo.Abp.ObjectExtending.TestObjects; namespace Volo.Abp.AutoMapper.SampleClasses { @@ -7,6 +8,9 @@ namespace Volo.Abp.AutoMapper.SampleClasses public MyMapProfile() { CreateMap().ReverseMap(); + + CreateMap() + .MapExtraProperties(); } } } diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs index 30db2aba71..6dcee4d5b2 100644 --- a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs @@ -4,7 +4,10 @@ using Volo.Abp.Threading; namespace Volo.Abp.ObjectExtending { - [DependsOn(typeof(AbpObjectExtendingModule))] + [DependsOn( + typeof(AbpObjectExtendingModule), + typeof(AbpTestBaseModule) + )] public class AbpObjectExtendingTestModule : AbpModule { private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs index 727ec25646..36d1f1988b 100644 --- a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs @@ -8,6 +8,7 @@ namespace Volo.Abp.ObjectExtending public class HasExtraPropertiesObjectExtendingExtensions_Tests : AbpObjectExtendingTestBase { private readonly ExtensibleTestPerson _person; + private readonly ExtensibleTestPersonDto _personDto; public HasExtraPropertiesObjectExtendingExtensions_Tests() { @@ -16,58 +17,57 @@ namespace Volo.Abp.ObjectExtending .SetProperty("Age", 42) .SetProperty("ChildCount", 2) .SetProperty("Sex", "male"); + + _personDto = new ExtensibleTestPersonDto() + .SetProperty("ExistingDtoProperty", "existing-value"); } [Fact] public void MapExtraPropertiesTo_Should_Only_Map_Defined_Properties_By_Default() { - var personDto = new ExtensibleTestPersonDto(); - - _person.MapExtraPropertiesTo(personDto); + _person.MapExtraPropertiesTo(_personDto); - personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes - personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination - personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source - personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + _personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes + _personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination + _personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source + _personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + _personDto.GetProperty("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values } [Fact] public void MapExtraPropertiesTo_Should_Only_Map_Source_Defined_Properties_If_Requested() { - var personDto = new ExtensibleTestPersonDto(); - - _person.MapExtraPropertiesTo(personDto, MappingPropertyDefinitionCheck.Source); + _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionCheck.Source); - personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes - personDto.GetProperty("Age").ShouldBe(42); //Defined in source - personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source - personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + _personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes + _personDto.GetProperty("Age").ShouldBe(42); //Defined in source + _personDto.HasProperty("ChildCount").ShouldBeFalse(); //Not defined in the source + _personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + _personDto.GetProperty("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values } [Fact] public void MapExtraPropertiesTo_Should_Only_Map_Destination_Defined_Properties_If_Requested() { - var personDto = new ExtensibleTestPersonDto(); + _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionCheck.Destination); - _person.MapExtraPropertiesTo(personDto, MappingPropertyDefinitionCheck.Destination); - - personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes - personDto.GetProperty("ChildCount").ShouldBe(2); //Defined in destination - personDto.HasProperty("Age").ShouldBeFalse(); //Not defined in destination - personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + _personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes + _personDto.GetProperty("ChildCount").ShouldBe(2); //Defined in destination + _personDto.HasProperty("Age").ShouldBeFalse(); //Not defined in destination + _personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes + _personDto.GetProperty("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values } [Fact] public void MapExtraPropertiesTo_Should_Copy_all_With_No_Property_Definition_Check() { - var personDto = new ExtensibleTestPersonDto(); - - _person.MapExtraPropertiesTo(personDto, MappingPropertyDefinitionCheck.None); + _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionCheck.None); - personDto.GetProperty("Name").ShouldBe("John"); - personDto.GetProperty("Age").ShouldBe(42); - personDto.GetProperty("ChildCount").ShouldBe(2); - personDto.GetProperty("Sex").ShouldBe("male"); + _personDto.GetProperty("Name").ShouldBe("John"); + _personDto.GetProperty("Age").ShouldBe(42); + _personDto.GetProperty("ChildCount").ShouldBe(2); + _personDto.GetProperty("Sex").ShouldBe("male"); + _personDto.GetProperty("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values } } }