diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index e78e9628c1..664e35e9b0 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -8,7 +8,7 @@ namespace AutoMapper { public static IMappingExpression MapExtraProperties( this IMappingExpression mappingExpression, - MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) + MappingPropertyDefinitionChecks? definitionChecks = null) where TDestination : IHasExtraProperties where TSource : IHasExtraProperties { 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 25156f298c..6b687fcf81 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using JetBrains.Annotations; using Volo.Abp.Data; @@ -25,7 +24,7 @@ namespace Volo.Abp.ObjectExtending public static void MapExtraPropertiesTo( [NotNull] this TSource source, [NotNull] TDestination destination, - MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) + MappingPropertyDefinitionChecks? definitionChecks = null) where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { @@ -58,7 +57,7 @@ namespace Volo.Abp.ObjectExtending public static void MapExtraPropertiesTo( [NotNull] Dictionary sourceDictionary, [NotNull] Dictionary destinationDictionary, - MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) + MappingPropertyDefinitionChecks? definitionChecks = null) where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { @@ -90,7 +89,7 @@ namespace Volo.Abp.ObjectExtending [NotNull] Type destinationType, [NotNull] Dictionary sourceDictionary, [NotNull] Dictionary destinationDictionary, - MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) + MappingPropertyDefinitionChecks? definitionChecks = null) { Check.AssignableTo(sourceType, nameof(sourceType)); Check.AssignableTo(destinationType, nameof(destinationType)); @@ -98,78 +97,120 @@ namespace Volo.Abp.ObjectExtending Check.NotNull(destinationDictionary, nameof(destinationDictionary)); var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType); - if (definitionChecks.HasFlag(MappingPropertyDefinitionChecks.Source) && - sourceObjectExtension == null) - { - return; - } - var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType); - if (definitionChecks.HasFlag(MappingPropertyDefinitionChecks.Destination) && - destinationObjectExtension == null) - { - return; - } - if (definitionChecks == MappingPropertyDefinitionChecks.None) + foreach (var keyValue in sourceDictionary) { - foreach (var keyValue in sourceDictionary) + if (CanMapProperty( + keyValue.Key, + sourceObjectExtension, + destinationObjectExtension, + definitionChecks)) { destinationDictionary[keyValue.Key] = keyValue.Value; } } - else if (definitionChecks == MappingPropertyDefinitionChecks.Source) - { - Debug.Assert(sourceObjectExtension != null, nameof(sourceObjectExtension) + " != null"); + } + + //TODO: Move these methods to a class like ObjectExtensionHelper + + public static bool CanMapProperty( + [NotNull] string propertyName, + MappingPropertyDefinitionChecks? definitionChecks = null) + { + return CanMapProperty( + typeof(TSource), + typeof(TDestination), + propertyName, + definitionChecks + ); + } + + public static bool CanMapProperty( + [NotNull] Type sourceType, + [NotNull] Type destinationType, + [NotNull] string propertyName, + MappingPropertyDefinitionChecks? definitionChecks = null) + { + Check.AssignableTo(sourceType, nameof(sourceType)); + Check.AssignableTo(destinationType, nameof(destinationType)); + Check.NotNull(propertyName, nameof(propertyName)); + + var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType); + var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType); + + return CanMapProperty( + propertyName, + sourceObjectExtension, + destinationObjectExtension, + definitionChecks); + } - foreach (var property in sourceObjectExtension.GetProperties()) + private static bool CanMapProperty( + [NotNull] string propertyName, + [CanBeNull] ObjectExtensionInfo sourceObjectExtension, + [CanBeNull] ObjectExtensionInfo destinationObjectExtension, + MappingPropertyDefinitionChecks? definitionChecks = null) + { + Check.NotNull(propertyName, nameof(propertyName)); + + if (definitionChecks != null) + { + if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Source)) { - if (!sourceDictionary.ContainsKey(property.Name)) + if (sourceObjectExtension == null) { - continue; + return false; } - destinationDictionary[property.Name] = sourceDictionary[property.Name]; + if (!sourceObjectExtension.HasProperty(propertyName)) + { + return false; + } } - } - else if (definitionChecks == MappingPropertyDefinitionChecks.Destination) - { - Debug.Assert(destinationObjectExtension != null, nameof(destinationObjectExtension) + " != null"); - foreach (var keyValue in sourceDictionary) + if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Destination)) { - if (!destinationObjectExtension.HasProperty(keyValue.Key)) + if (destinationObjectExtension == null) { - continue; + return false; } - destinationDictionary[keyValue.Key] = keyValue.Value; + if (!destinationObjectExtension.HasProperty(propertyName)) + { + return false; + } } + + return true; } - else if (definitionChecks == MappingPropertyDefinitionChecks.Both) + else { - Debug.Assert(sourceObjectExtension != null, nameof(sourceObjectExtension) + " != null"); - Debug.Assert(destinationObjectExtension != null, nameof(destinationObjectExtension) + " != null"); + var sourcePropertyDefinition = sourceObjectExtension?.GetPropertyOrNull(propertyName); + var destinationPropertyDefinition = destinationObjectExtension?.GetPropertyOrNull(propertyName); - foreach (var property in sourceObjectExtension.GetProperties()) + if (sourcePropertyDefinition != null) { - if (!sourceDictionary.ContainsKey(property.Name)) + if (destinationPropertyDefinition != null) { - continue; + return true; } - if (!destinationObjectExtension.HasProperty(property.Name)) + if (sourcePropertyDefinition.CheckPairDefinitionOnMapping == false) { - continue; + return true; } - - destinationDictionary[property.Name] = sourceDictionary[property.Name]; } - } - else - { - throw new NotImplementedException(definitionChecks + " was not implemented!"); + else if (destinationPropertyDefinition != null) + { + if (destinationPropertyDefinition.CheckPairDefinitionOnMapping == false) + { + return true; + } + } + + return false; } } } -} +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs index af5d0c2ce4..2edae9a3f8 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -15,6 +15,20 @@ namespace Volo.Abp.ObjectExtending [NotNull] public Type Type { get; } + /// + /// Indicates whether to check the other side of the object mapping + /// if it explicitly defines the property. This property is used in; + /// + /// * .MapExtraPropertiesTo() extension method. + /// * .MapExtraProperties() configuration for the AutoMapper. + /// + /// It this is true, these methods check if the mapping object + /// has defined the property using the . + /// + /// Default: null (unspecified, uses the default logic). + /// + public bool? CheckPairDefinitionOnMapping { get; set; } + [NotNull] public Dictionary Configuration { get; } 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 6dcee4d5b2..470bb547e5 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 @@ -19,6 +19,7 @@ namespace Volo.Abp.ObjectExtending ObjectExtensionManager.Instance .AddOrUpdateProperty("Name") .AddOrUpdateProperty("Age") + .AddOrUpdateProperty("NoPairCheck", options => options.CheckPairDefinitionOnMapping = false) .AddOrUpdateProperty("Name") .AddOrUpdateProperty("ChildCount"); }); 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 a51d9514b2..7ba213b81c 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 @@ -16,7 +16,8 @@ namespace Volo.Abp.ObjectExtending .SetProperty("Name", "John") .SetProperty("Age", 42) .SetProperty("ChildCount", 2) - .SetProperty("Sex", "male"); + .SetProperty("Sex", "male") + .SetProperty("NoPairCheck", "test-value"); _personDto = new ExtensibleTestPersonDto() .SetProperty("ExistingDtoProperty", "existing-value"); @@ -31,6 +32,7 @@ namespace Volo.Abp.ObjectExtending _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("NoPairCheck").ShouldBe("test-value"); //CheckPairDefinitionOnMapping = false _personDto.GetProperty("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values }