From 6564d6d7e4e6d97d6067e0eeb835f6935d8e50f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Mar 2020 18:45:04 +0300 Subject: [PATCH 01/24] Added Volo.Abp.ObjectExtending package. --- framework/Volo.Abp.sln | 9 ++++- .../AbpAutoMapperExtensibleDtoExtensions.cs | 35 ++++++++++++++++ .../Volo.Abp.AutoMapper.csproj | 1 + .../Abp/AutoMapper/AbpAutoMapperModule.cs | 5 ++- .../src/Volo.Abp.Data/Volo.Abp.Data.csproj | 1 + .../Volo/Abp/Data/AbpDataModule.cs | 4 +- .../Application/Dtos/ExtensibleEntityDto.cs | 28 +++++++++++++ .../Volo.Abp.ObjectExtending/FodyWeavers.xml | 3 ++ .../Volo.Abp.ObjectExtending/FodyWeavers.xsd | 30 ++++++++++++++ .../Volo.Abp.ObjectExtending.csproj | 21 ++++++++++ .../Abp/Data/HasExtraPropertiesExtensions.cs | 0 .../Volo/Abp/Data/IHasExtraProperties.cs | 0 .../AbpObjectExtendingModule.cs | 9 +++++ .../Abp/ObjectExtending/ExtensibleObject.cs | 17 ++++++++ .../ObjectExtending/ObjectExtensionInfo.cs | 14 +++++++ .../ObjectExtending/ObjectExtensionManager.cs | 40 +++++++++++++++++++ .../ObjectExtensionPropertyInfo.cs | 18 +++++++++ nupkg/common.ps1 | 1 + 18 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs create mode 100644 framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xml create mode 100644 framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xsd create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo.Abp.ObjectExtending.csproj rename framework/src/{Volo.Abp.Data => Volo.Abp.ObjectExtending}/Volo/Abp/Data/HasExtraPropertiesExtensions.cs (100%) rename framework/src/{Volo.Abp.Data => Volo.Abp.ObjectExtending}/Volo/Abp/Data/IHasExtraProperties.cs (100%) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/AbpObjectExtendingModule.cs create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 88c8385b63..16327abcad 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -273,7 +273,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo", "test\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Demo.csproj", "{0C498CF2-D052-4BF7-AD35-509A90F69707}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Http.Client.IdentityModel.Web.Tests", "test\Volo.Abp.Http.Client.IdentityModel.Web.Tests\Volo.Abp.Http.Client.IdentityModel.Web.Tests.csproj", "{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Client.IdentityModel.Web.Tests", "test\Volo.Abp.Http.Client.IdentityModel.Web.Tests\Volo.Abp.Http.Client.IdentityModel.Web.Tests.csproj", "{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.ObjectExtending", "src\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj", "{D1815C77-16D6-4F99-8814-69065CD89FB3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -817,6 +819,10 @@ Global {E1963439-2BE5-4DB5-8438-2A9A792A1ADA}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1963439-2BE5-4DB5-8438-2A9A792A1ADA}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1963439-2BE5-4DB5-8438-2A9A792A1ADA}.Release|Any CPU.Build.0 = Release|Any CPU + {D1815C77-16D6-4F99-8814-69065CD89FB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1815C77-16D6-4F99-8814-69065CD89FB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1815C77-16D6-4F99-8814-69065CD89FB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1815C77-16D6-4F99-8814-69065CD89FB3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -956,6 +962,7 @@ Global {29E42ADB-85F8-44AE-A9B0-078F84C1B866} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {0C498CF2-D052-4BF7-AD35-509A90F69707} = {447C8A77-E5F0-4538-8687-7383196D04EA} {E1963439-2BE5-4DB5-8438-2A9A792A1ADA} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {D1815C77-16D6-4F99-8814-69065CD89FB3} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs new file mode 100644 index 0000000000..a0a7648337 --- /dev/null +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using Volo.Abp.Data; +using Volo.Abp.ObjectExtending; + +namespace AutoMapper +{ + public static class AbpAutoMapperExtensibleDtoExtensions + { + public static IMappingExpression MapExtraProperties( + this IMappingExpression mappingExpression) + where TDestination : IHasExtraProperties + where TSource : IHasExtraProperties + { + var properties = ObjectExtensionManager.GetProperties(); + return mappingExpression + .ForMember( + x => x.ExtraProperties, + y => y.MapFrom( + (source, dto, extraProps) => + { + var result = extraProps.IsNullOrEmpty() + ? new Dictionary() + : new Dictionary(extraProps); + + foreach (var property in properties) + { + result[property.Name] = source.ExtraProperties[property.Name]; + } + + return result; + }) + ); + } + } +} diff --git a/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj b/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj index e6146fedde..327f2078d1 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj +++ b/framework/src/Volo.Abp.AutoMapper/Volo.Abp.AutoMapper.csproj @@ -15,6 +15,7 @@ + diff --git a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs index ba3ef2ada8..1590e879b1 100644 --- a/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs +++ b/framework/src/Volo.Abp.AutoMapper/Volo/Abp/AutoMapper/AbpAutoMapperModule.cs @@ -3,11 +3,14 @@ using AutoMapper; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectMapping; namespace Volo.Abp.AutoMapper { - [DependsOn(typeof(AbpObjectMappingModule))] + [DependsOn( + typeof(AbpObjectMappingModule), + typeof(AbpObjectExtendingModule))] public class AbpAutoMapperModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj b/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj index 7a53782ae1..cde2718a56 100644 --- a/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj +++ b/framework/src/Volo.Abp.Data/Volo.Abp.Data.csproj @@ -16,6 +16,7 @@ + diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs index 2414803970..8c9643012e 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs @@ -2,13 +2,15 @@ using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; using Volo.Abp.Uow; namespace Volo.Abp.Data { [DependsOn( + typeof(AbpObjectExtendingModule), typeof(AbpUnitOfWorkModule) - )] + )] public class AbpDataModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs new file mode 100644 index 0000000000..63d07bcdcf --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleEntityDto.cs @@ -0,0 +1,28 @@ +using System; +using Volo.Abp.ObjectExtending; + +namespace Volo.Abp.Application.Dtos +{ + [Serializable] + public abstract class ExtensibleEntityDto : ExtensibleObject, IEntityDto + { + /// + /// Id of the entity. + /// + public TKey Id { get; set; } + + public override string ToString() + { + return $"[DTO: {GetType().Name}] Id = {Id}"; + } + } + + [Serializable] + public abstract class ExtensibleEntityDto : ExtensibleObject, IEntityDto + { + public override string ToString() + { + return $"[DTO: {GetType().Name}]"; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xml b/framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xsd b/framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo.Abp.ObjectExtending.csproj b/framework/src/Volo.Abp.ObjectExtending/Volo.Abp.ObjectExtending.csproj new file mode 100644 index 0000000000..43da943f8b --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo.Abp.ObjectExtending.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.0 + Volo.Abp.ObjectExtending + Volo.Abp.ObjectExtending + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/HasExtraPropertiesExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs similarity index 100% rename from framework/src/Volo.Abp.Data/Volo/Abp/Data/HasExtraPropertiesExtensions.cs rename to framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/HasExtraPropertiesExtensions.cs diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IHasExtraProperties.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/IHasExtraProperties.cs similarity index 100% rename from framework/src/Volo.Abp.Data/Volo/Abp/Data/IHasExtraProperties.cs rename to framework/src/Volo.Abp.ObjectExtending/Volo/Abp/Data/IHasExtraProperties.cs diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/AbpObjectExtendingModule.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/AbpObjectExtendingModule.cs new file mode 100644 index 0000000000..9392429fd3 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/AbpObjectExtendingModule.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Modularity; + +namespace Volo.Abp.ObjectExtending +{ + public class AbpObjectExtendingModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs new file mode 100644 index 0000000000..07243c9dca --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObject.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Data; + +namespace Volo.Abp.ObjectExtending +{ + [Serializable] + public class ExtensibleObject : IHasExtraProperties + { + public Dictionary ExtraProperties { get; protected set; } + + public ExtensibleObject() + { + ExtraProperties = new Dictionary(); + } + } +} diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs new file mode 100644 index 0000000000..58a8c445bb --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Volo.Abp.ObjectExtending +{ + public class ObjectExtensionInfo + { + public Dictionary Properties { get; } + + public ObjectExtensionInfo() + { + Properties = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs new file mode 100644 index 0000000000..7a8701c9bf --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Volo.Abp.Data; + +namespace Volo.Abp.ObjectExtending +{ + public static class ObjectExtensionManager + { + //TODO: Concurrent, to allow extend on runtime! + private static Dictionary Extensions { get; } + + static ObjectExtensionManager() + { + Extensions = new Dictionary(); + } + + public static ObjectExtensionPropertyInfo AddProperty( + string propertyName, + Action configureAction = null) + { + var extensionInfo = Extensions.GetOrAdd(typeof(TDto), () => new ObjectExtensionInfo()); + var propertyInfo = extensionInfo.Properties.GetOrAdd(propertyName, () => new ObjectExtensionPropertyInfo(propertyName)); + configureAction?.Invoke(propertyInfo); + return propertyInfo; + } + + public static ImmutableList GetProperties() + where TDto : IHasExtraProperties + { + var extensionInfo = Extensions.GetOrDefault(typeof(TDto)); + if (extensionInfo == null) + { + return new ObjectExtensionPropertyInfo[0].ToImmutableList(); //TODO: Return an empty one! + } + + return extensionInfo.Properties.Values.ToImmutableList(); + } + } +} \ 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 new file mode 100644 index 0000000000..f232a803ff --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.ObjectExtending +{ + public class ObjectExtensionPropertyInfo + { + public string Name { get; } + + public List ValidationAttributes { get; } + + public ObjectExtensionPropertyInfo(string name) + { + Name = name; + ValidationAttributes = new List(); + } + } +} diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index ea84e52b28..f9e1263908 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -91,6 +91,7 @@ $projects = ( "framework/src/Volo.Abp.MongoDB", "framework/src/Volo.Abp.MultiTenancy", "framework/src/Volo.Abp.Minify", + "framework/src/Volo.Abp.ObjectExtending", "framework/src/Volo.Abp.ObjectMapping", "framework/src/Volo.Abp.Quartz", "framework/src/Volo.Abp.RabbitMQ", From 805c3a2973067f1278cce1505943829d969e24a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Mar 2020 21:00:05 +0300 Subject: [PATCH 02/24] Make ObjectExtensionManager singleton, instead of static. --- .../AbpAutoMapperExtensibleDtoExtensions.cs | 2 +- .../Abp/ObjectExtending/ObjectExtensionManager.cs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index a0a7648337..e305cbce8a 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -11,7 +11,7 @@ namespace AutoMapper where TDestination : IHasExtraProperties where TSource : IHasExtraProperties { - var properties = ObjectExtensionManager.GetProperties(); + var properties = ObjectExtensionManager.Instance.GetProperties(); return mappingExpression .ForMember( x => x.ExtraProperties, diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs index 7a8701c9bf..c266964bc3 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -5,17 +5,18 @@ using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending { - public static class ObjectExtensionManager + public class ObjectExtensionManager { - //TODO: Concurrent, to allow extend on runtime! - private static Dictionary Extensions { get; } + public static ObjectExtensionManager Instance { get; } = new ObjectExtensionManager(); - static ObjectExtensionManager() + private Dictionary Extensions { get; } + + private ObjectExtensionManager() { Extensions = new Dictionary(); } - public static ObjectExtensionPropertyInfo AddProperty( + public ObjectExtensionPropertyInfo AddProperty( string propertyName, Action configureAction = null) { @@ -25,7 +26,7 @@ namespace Volo.Abp.ObjectExtending return propertyInfo; } - public static ImmutableList GetProperties() + public ImmutableList GetProperties() where TDto : IHasExtraProperties { var extensionInfo = Extensions.GetOrDefault(typeof(TDto)); From 7667f474d8ea3922e9bfeefd2dd87777b1f66e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Mar 2020 21:14:20 +0300 Subject: [PATCH 03/24] Added Extensible Entity DTO classes. --- .../Dtos/AuditedEntityWithUserDto.cs | 2 + .../Dtos/CreationAuditedEntityWithUserDto.cs | 4 +- .../Dtos/ExtensibleAuditedEntityDto.cs | 35 ++++++++++++++ .../ExtensibleAuditedEntityWithUserDto.cs | 40 ++++++++++++++++ .../ExtensibleCreationAuditedEntityDto.cs | 35 ++++++++++++++ ...ensibleCreationAuditedEntityWithUserDto.cs | 32 +++++++++++++ .../Dtos/ExtensibleFullAuditedEntityDto.cs | 41 +++++++++++++++++ .../ExtensibleFullAuditedEntityWithUserDto.cs | 46 +++++++++++++++++++ .../Dtos/FullAuditedEntityWithUserDto.cs | 6 ++- 9 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityDto.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityWithUserDto.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityDto.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityWithUserDto.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityDto.cs create mode 100644 framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityWithUserDto.cs diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/AuditedEntityWithUserDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/AuditedEntityWithUserDto.cs index c5dd43de14..8a8e99d869 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/AuditedEntityWithUserDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/AuditedEntityWithUserDto.cs @@ -5,6 +5,7 @@ namespace Volo.Abp.Application.Dtos { /// /// This class can be inherited by DTO classes to implement interface. + /// It has the and objects as a DTOs represent the related user. /// /// Type of the User DTO [Serializable] @@ -19,6 +20,7 @@ namespace Volo.Abp.Application.Dtos /// /// This class can be inherited by DTO classes to implement interface. + /// It has the and objects as a DTOs represent the related user. /// /// Type of primary key /// Type of the User DTO diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/CreationAuditedEntityWithUserDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/CreationAuditedEntityWithUserDto.cs index 51e3c9018a..5d6260ebcd 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/CreationAuditedEntityWithUserDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/CreationAuditedEntityWithUserDto.cs @@ -5,6 +5,7 @@ namespace Volo.Abp.Application.Dtos { /// /// This class can be inherited by DTO classes to implement interface. + /// It also has the object as a DTO represents the user. /// /// Type of the User DTO [Serializable] @@ -14,7 +15,8 @@ namespace Volo.Abp.Application.Dtos } /// - /// This class can be inherited by DTO classes to implement interface. + /// This class can be inherited by DTO classes to implement interface. + /// It also has the object as a DTO represents the user. /// /// Type of primary key /// Type of the User DTO diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityDto.cs new file mode 100644 index 0000000000..6be7d38070 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityDto.cs @@ -0,0 +1,35 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Data; + +namespace Volo.Abp.Application.Dtos +{ + /// + /// This class can be inherited by DTO classes to implement interface. + /// It also implements the interface. + /// + /// Type of primary key + [Serializable] + public abstract class ExtensibleAuditedEntityDto : ExtensibleCreationAuditedEntityDto, IAuditedObject + { + /// + public DateTime? LastModificationTime { get; set; } + + /// + public Guid? LastModifierId { get; set; } + } + + /// + /// This class can be inherited by DTO classes to implement interface. + /// It also implements the interface. + /// + [Serializable] + public abstract class ExtensibleAuditedEntityDto : ExtensibleCreationAuditedEntityDto, IAuditedObject + { + /// + public DateTime? LastModificationTime { get; set; } + + /// + public Guid? LastModifierId { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityWithUserDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityWithUserDto.cs new file mode 100644 index 0000000000..94086c119b --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleAuditedEntityWithUserDto.cs @@ -0,0 +1,40 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Data; + +namespace Volo.Abp.Application.Dtos +{ + /// + /// This class can be inherited by DTO classes to implement interface. + /// It has the and objects as a DTOs represent the related user. + /// It also implements the interface. + /// + /// Type of primary key + /// Type of the User DTO + [Serializable] + public abstract class ExtensibleAuditedEntityWithUserDto : ExtensibleAuditedEntityDto, IAuditedObject + { + /// + public TUserDto Creator { get; set; } + + /// + public TUserDto LastModifier { get; set; } + } + + /// + /// This class can be inherited by DTO classes to implement interface. + /// It has the and objects as a DTOs represent the related user. + /// It also implements the interface. + /// + /// Type of the User DTO + [Serializable] + public abstract class ExtensibleAuditedEntityWithUserDto : ExtensibleAuditedEntityDto, + IAuditedObject + { + /// + public TUserDto Creator { get; set; } + + /// + public TUserDto LastModifier { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityDto.cs new file mode 100644 index 0000000000..1de40ff4d5 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityDto.cs @@ -0,0 +1,35 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Data; + +namespace Volo.Abp.Application.Dtos +{ + /// + /// This class can be inherited by DTO classes to implement interface. + /// It also implements the interface. + /// + /// Type of primary key + [Serializable] + public abstract class ExtensibleCreationAuditedEntityDto : ExtensibleEntityDto, ICreationAuditedObject + { + /// + public DateTime CreationTime { get; set; } + + /// + public Guid? CreatorId { get; set; } + } + + /// + /// This class can be inherited by DTO classes to implement interface. + /// It also implements the interface. + /// + [Serializable] + public abstract class ExtensibleCreationAuditedEntityDto : ExtensibleEntityDto, ICreationAuditedObject + { + /// + public DateTime CreationTime { get; set; } + + /// + public Guid? CreatorId { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityWithUserDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityWithUserDto.cs new file mode 100644 index 0000000000..d5352d5b03 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleCreationAuditedEntityWithUserDto.cs @@ -0,0 +1,32 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Data; + +namespace Volo.Abp.Application.Dtos +{ + /// + /// This class can be inherited by DTO classes to implement interface. + /// It has the object as a DTO represents the user. + /// It also implements the interface. + /// + /// Type of primary key + /// Type of the User DTO + [Serializable] + public abstract class ExtensibleCreationAuditedEntityWithUserDto : ExtensibleCreationAuditedEntityDto, ICreationAuditedObject + { + public TUserDto Creator { get; set; } + } + + /// + /// This class can be inherited by DTO classes to implement interface. + /// It has the object as a DTO represents the user. + /// It also implements the interface. + /// + /// Type of the User DTO + [Serializable] + public abstract class ExtensibleCreationAuditedEntityWithUserDto : ExtensibleCreationAuditedEntityDto, + ICreationAuditedObject + { + public TUserDto Creator { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityDto.cs new file mode 100644 index 0000000000..d72bf8135d --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityDto.cs @@ -0,0 +1,41 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Data; + +namespace Volo.Abp.Application.Dtos +{ + /// + /// This class can be inherited by DTO classes to implement interface. + /// It also implements the interface. + /// + /// Type of primary key + [Serializable] + public abstract class ExtensibleFullAuditedEntityDto : ExtensibleAuditedEntityDto, IFullAuditedObject + { + /// + public bool IsDeleted { get; set; } + + /// + public Guid? DeleterId { get; set; } + + /// + public DateTime? DeletionTime { get; set; } + } + + /// + /// This class can be inherited by DTO classes to implement interface. + /// It also implements the interface. + /// + [Serializable] + public abstract class ExtensibleFullAuditedEntityDto : ExtensibleAuditedEntityDto, IFullAuditedObject + { + /// + public bool IsDeleted { get; set; } + + /// + public Guid? DeleterId { get; set; } + + /// + public DateTime? DeletionTime { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityWithUserDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityWithUserDto.cs new file mode 100644 index 0000000000..b5e68e7cb7 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/ExtensibleFullAuditedEntityWithUserDto.cs @@ -0,0 +1,46 @@ +using System; +using Volo.Abp.Auditing; +using Volo.Abp.Data; + +namespace Volo.Abp.Application.Dtos +{ + /// + /// This class can be inherited by DTO classes to implement interface. + /// It has the , and objects as a DTOs represent the related user. + /// It also implements the interface. + /// + /// Type of primary key + /// Type of the User + [Serializable] + public abstract class ExtensibleFullAuditedEntityWithUserDto : ExtensibleFullAuditedEntityDto, IFullAuditedObject + { + /// + public TUserDto Creator { get; set; } + + /// + public TUserDto LastModifier { get; set; } + + /// + public TUserDto Deleter { get; set; } + } + + /// + /// This class can be inherited by DTO classes to implement interface. + /// It has the , and objects as a DTOs represent the related user. + /// It also implements the interface. + /// + /// Type of the User + [Serializable] + public abstract class ExtensibleFullAuditedEntityWithUserDto : ExtensibleFullAuditedEntityDto, + IFullAuditedObject + { + /// + public TUserDto Creator { get; set; } + + /// + public TUserDto LastModifier { get; set; } + + /// + public TUserDto Deleter { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/FullAuditedEntityWithUserDto.cs b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/FullAuditedEntityWithUserDto.cs index 91e31250fb..30b1f0b2ba 100644 --- a/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/FullAuditedEntityWithUserDto.cs +++ b/framework/src/Volo.Abp.Ddd.Application.Contracts/Volo/Abp/Application/Dtos/FullAuditedEntityWithUserDto.cs @@ -4,7 +4,8 @@ using Volo.Abp.Auditing; namespace Volo.Abp.Application.Dtos { /// - /// This class can be inherited by DTO classes to implement interface. + /// This class can be inherited by DTO classes to implement interface. + /// It has the , and objects as a DTOs represent the related user. /// /// Type of the User [Serializable] @@ -21,7 +22,8 @@ namespace Volo.Abp.Application.Dtos } /// - /// This class can be inherited by DTO classes to implement interface. + /// This class can be inherited by DTO classes to implement interface. + /// It has the , and objects as a DTOs represent the related user. /// /// Type of primary key /// Type of the User From 8ea1c34cb95fb6fa6edb192de47b2bd7877e3153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Fri, 27 Mar 2020 21:58:20 +0300 Subject: [PATCH 04/24] Added HasExtraPropertiesObjectExtendingExtensions --- .../AbpAutoMapperExtensibleDtoExtensions.cs | 5 ++++- ...xtraPropertiesObjectExtendingExtensions.cs | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index e305cbce8a..e2420ec510 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -24,7 +24,10 @@ namespace AutoMapper foreach (var property in properties) { - result[property.Name] = source.ExtraProperties[property.Name]; + if (source.ExtraProperties.ContainsKey(property.Name)) + { + result[property.Name] = source.ExtraProperties[property.Name]; + } } return result; diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs new file mode 100644 index 0000000000..c6618b009e --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -0,0 +1,22 @@ +using Volo.Abp.Data; + +namespace Volo.Abp.ObjectExtending +{ + public static class HasExtraPropertiesObjectExtendingExtensions + { + public static void MapExtraPropertiesTo(this TSource source, TDestination destination) + where TSource : IHasExtraProperties + where TDestination : IHasExtraProperties + { + var extensionPropertyInfos = ObjectExtensionManager.Instance.GetProperties(); + + foreach (var extensionPropertyInfo in extensionPropertyInfos) + { + if (source.ExtraProperties.ContainsKey(extensionPropertyInfo.Name)) + { + destination.ExtraProperties[extensionPropertyInfo.Name] = source.ExtraProperties[extensionPropertyInfo.Name]; + } + } + } + } +} From 26a26a1d581d6f6f53d05989b38699a9c1a974f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 12:52:22 +0300 Subject: [PATCH 05/24] Added Configuration --- .../Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs | 3 +++ .../Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index 58a8c445bb..9deda6fed1 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -6,9 +6,12 @@ namespace Volo.Abp.ObjectExtending { public Dictionary Properties { get; } + public Dictionary Configuration { get; } + public ObjectExtensionInfo() { Properties = new Dictionary(); + Configuration = new Dictionary(); } } } \ 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 f232a803ff..981bfd3040 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -9,10 +9,13 @@ namespace Volo.Abp.ObjectExtending public List ValidationAttributes { get; } + public Dictionary Configuration { get; } + public ObjectExtensionPropertyInfo(string name) { Name = name; ValidationAttributes = new List(); + Configuration = new Dictionary(); } } } From bf939737304bf391912b731aa51efd2538757c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 13:10:33 +0300 Subject: [PATCH 06/24] Refactor ObjectExtensionManager --- .../AbpAutoMapperExtensibleDtoExtensions.cs | 2 +- ...xtraPropertiesObjectExtendingExtensions.cs | 2 +- .../ObjectExtending/ObjectExtensionInfo.cs | 28 +++++++++++++++-- .../ObjectExtending/ObjectExtensionManager.cs | 31 ++++++------------- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index e2420ec510..dc5741e07f 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -11,7 +11,7 @@ namespace AutoMapper where TDestination : IHasExtraProperties where TSource : IHasExtraProperties { - var properties = ObjectExtensionManager.Instance.GetProperties(); + var properties = ObjectExtensionManager.Instance.For().GetProperties(); return mappingExpression .ForMember( x => x.ExtraProperties, 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 c6618b009e..86e288c932 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.ObjectExtending where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { - var extensionPropertyInfos = ObjectExtensionManager.Instance.GetProperties(); + var extensionPropertyInfos = ObjectExtensionManager.Instance.For().GetProperties(); foreach (var extensionPropertyInfo in extensionPropertyInfos) { diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index 9deda6fed1..04698c6b69 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -1,17 +1,41 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; namespace Volo.Abp.ObjectExtending { public class ObjectExtensionInfo { + public Type Type { get; } + public Dictionary Properties { get; } public Dictionary Configuration { get; } - public ObjectExtensionInfo() + public ObjectExtensionInfo(Type type) { + Type = type; Properties = new Dictionary(); Configuration = new Dictionary(); } + + public ObjectExtensionPropertyInfo AddProperty( + string propertyName, + Action configureAction = null) + { + var propertyInfo = Properties.GetOrAdd( + propertyName, + () => new ObjectExtensionPropertyInfo(propertyName) + ); + + configureAction?.Invoke(propertyInfo); + + return propertyInfo; + } + + public ImmutableList GetProperties() + { + return Properties.Values.ToImmutableList(); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs index c266964bc3..ad820522f2 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; -using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending { @@ -9,33 +7,24 @@ namespace Volo.Abp.ObjectExtending { public static ObjectExtensionManager Instance { get; } = new ObjectExtensionManager(); - private Dictionary Extensions { get; } + private Dictionary ObjectsExtensions { get; } private ObjectExtensionManager() { - Extensions = new Dictionary(); + ObjectsExtensions = new Dictionary(); } - public ObjectExtensionPropertyInfo AddProperty( - string propertyName, - Action configureAction = null) + public ObjectExtensionInfo For( + Action configureAction = null) { - var extensionInfo = Extensions.GetOrAdd(typeof(TDto), () => new ObjectExtensionInfo()); - var propertyInfo = extensionInfo.Properties.GetOrAdd(propertyName, () => new ObjectExtensionPropertyInfo(propertyName)); - configureAction?.Invoke(propertyInfo); - return propertyInfo; - } + var extensionInfo = ObjectsExtensions.GetOrAdd( + typeof(TObject), + () => new ObjectExtensionInfo(typeof(TObject)) + ); - public ImmutableList GetProperties() - where TDto : IHasExtraProperties - { - var extensionInfo = Extensions.GetOrDefault(typeof(TDto)); - if (extensionInfo == null) - { - return new ObjectExtensionPropertyInfo[0].ToImmutableList(); //TODO: Return an empty one! - } + configureAction?.Invoke(extensionInfo); - return extensionInfo.Properties.Values.ToImmutableList(); + return extensionInfo; } } } \ No newline at end of file From a3e9e0d533d7857f811c34acbe03de4a7f359aeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 17:51:32 +0300 Subject: [PATCH 07/24] Refactor ObjectExtensionManager & Update the documentation. Removed EntityExtensionManager merged functionality to ObjectExtensionManager. --- ...-Application-Modules-Extending-Entities.md | 4 +- docs/en/Entities.md | 2 +- docs/en/Entity-Framework-Core-Migrations.md | 15 +- docs/en/Entity-Framework-Core.md | 41 +++--- .../AbpAutoMapperExtensibleDtoExtensions.cs | 11 +- .../Abp/EntityFrameworkCore/AbpDbContext.cs | 35 +++-- .../Extensions/EntityExtensionInfo.cs | 14 -- .../Extensions/EntityExtensionManager.cs | 133 ------------------ .../Extensions/PropertyExtensionInfo.cs | 17 --- .../AbpEntityTypeBuilderExtensions.cs | 32 +++-- .../ExtraPropertiesValueConverter.cs | 15 +- .../EfCoreObjectExtensionInfoExtensions.cs | 37 +++++ .../EfCoreObjectExtensionManagerExtensions.cs | 75 ++++++++++ ...reObjectExtensionPropertyInfoExtensions.cs | 41 ++++++ ...tensionPropertyInfoEfCoreMappingOptions.cs | 31 ++++ ...xtraPropertiesObjectExtendingExtensions.cs | 2 +- .../ObjectExtending/ObjectExtensionInfo.cs | 4 +- .../ObjectExtending/ObjectExtensionManager.cs | 29 +++- .../ObjectExtensionPropertyInfo.cs | 13 +- .../Domain/TestEntityExtensionConfigurator.cs | 11 +- .../TestMigrationsDbContext.cs | 3 - .../EntityFrameworkCore/TestAppDbContext.cs | 3 - ...IdentityDbContextModelBuilderExtensions.cs | 1 - 23 files changed, 324 insertions(+), 245 deletions(-) delete mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionInfo.cs delete mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionManager.cs delete mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/PropertyExtensionInfo.cs create mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs create mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs create mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs create mode 100644 framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs diff --git a/docs/en/Customizing-Application-Modules-Extending-Entities.md b/docs/en/Customizing-Application-Modules-Extending-Entities.md index be8bda6068..376e7a1517 100644 --- a/docs/en/Customizing-Application-Modules-Extending-Entities.md +++ b/docs/en/Customizing-Application-Modules-Extending-Entities.md @@ -37,10 +37,10 @@ As mentioned above, all extra properties of an entity are stored as a single JSO To overcome the difficulties described above, ABP Framework entity extension system for the Entity Framework Core that allows you to use the same extra properties API defined above, but store a desired property as a separate field in the database table. -Assume that you want to add a `SocialSecurityNumber` to the `IdentityUser` entity of the [Identity Module](Modules/Identity.md). You can use the `EntityExtensionManager` static class: +Assume that you want to add a `SocialSecurityNumber` to the `IdentityUser` entity of the [Identity Module](Modules/Identity.md). You can use the `ObjectExtensionManager`: ````csharp -EntityExtensionManager.AddProperty( +ObjectExtensionManager.Instance.MapEfCoreProperty( "SocialSecurityNumber", b => { b.HasMaxLength(32); } ); diff --git a/docs/en/Entities.md b/docs/en/Entities.md index fee1a3618c..8a234b94a5 100644 --- a/docs/en/Entities.md +++ b/docs/en/Entities.md @@ -375,7 +375,7 @@ The way to store this dictionary in the database depends on the database provide * For [Entity Framework Core](Entity-Framework-Core.md), here are two type of configurations; * By default, it is stored in a single `ExtraProperties` field as a `JSON` string (that means all extra properties stored in a single database table field). Serializing to `JSON` and deserializing from the `JSON` are automatically done by the ABP Framework using the [value conversions](https://docs.microsoft.com/en-us/ef/core/modeling/value-conversions) system of the EF Core. - * If you want, you can use the `EntityExtensionManager` to define a separate table field for a desired extra property. Properties those are not configured through the `EntityExtensionManager` will continue to use a single `JSON` field as described above. This feature is especially useful when you are using a pre-built [application module](Modules/Index.md) and want to [extend its entities](Customizing-Application-Modules-Extending-Entities.md). See the [EF Core integration document](Entity-Framework-Core.md) to learn how to use the `EntityExtensionManager`. + * If you want, you can use the `ObjectExtensionManager` to define a separate table field for a desired extra property. Properties those are not configured through the `ObjectExtensionManager` will continue to use a single `JSON` field as described above. This feature is especially useful when you are using a pre-built [application module](Modules/Index.md) and want to [extend its entities](Customizing-Application-Modules-Extending-Entities.md). See the [EF Core integration document](Entity-Framework-Core.md) to learn how to use the `ObjectExtensionManager`. * For [MongoDB](MongoDB.md), it is stored as a **regular field**, since MongoDB naturally supports this kind of [extra elements](https://mongodb.github.io/mongo-csharp-driver/1.11/serialization/#supporting-extra-elements) system. ### Discussion for the Extra Properties diff --git a/docs/en/Entity-Framework-Core-Migrations.md b/docs/en/Entity-Framework-Core-Migrations.md index 5d2fff011c..fbe0f59d70 100644 --- a/docs/en/Entity-Framework-Core-Migrations.md +++ b/docs/en/Entity-Framework-Core-Migrations.md @@ -409,18 +409,19 @@ public static class MyProjectNameEntityExtensions { OneTimeRunner.Run(() => { - EntityExtensionManager.AddProperty( - "Title", - b => { b.HasMaxLength(128); } - ); + ObjectExtensionManager.Instance + .MapEfCoreProperty( + "Title", + builder => { builder.HasMaxLength(64); } + ); }); } } ```` -> Instead of hard-coded "Title" string, we suggest to use `nameof(AppRole.Title)`. +> Instead of hard-coded "Title" string, we suggest to use `nameof(AppRole.Title)` or use a constant string. -`EntityExtensionManager` is used to add properties to existing entities. Since `EntityExtensionManager` is static, we should call it once. `OneTimeRunner` is a simple utility class defined by the ABP Framework. +`ObjectExtensionManager` is used to add properties to existing entities. Since `ObjectExtensionManager.Instance` is a static instance (singleton), we should call it once. `OneTimeRunner` is a simple utility class defined by the ABP Framework. See the [EF Core integration documentation](Entity-Framework-Core.md) for more about the entity extension system. @@ -543,7 +544,7 @@ In this way, you can easily attach any type of value to an entity of a depended Entity extension system solves the main problem of the extra properties: It can store an extra property in a **standard table field** in the database. -All you need to do is to use the `EntityExtensionManager` to define the extra property as explained above, in the `AppRole` example. Then you can continue to use the same `GetProperty` and `SetProperty` methods defined above to get/set the related property on the entity, but this time stored as a separate field in the database. +All you need to do is to use the `ObjectExtensionManager` to define the extra property as explained above, in the `AppRole` example. Then you can continue to use the same `GetProperty` and `SetProperty` methods defined above to get/set the related property on the entity, but this time stored as a separate field in the database. ###### Creating a New Table diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index d908ce03f5..66f9d3c2f9 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -298,56 +298,57 @@ public class BookService > Important: You must reference to the `Volo.Abp.EntityFrameworkCore` package from the project you want to access to the DbContext. This breaks encapsulation, but this is what you want in that case. -## Extra Properties & Entity Extension Manager +## Extra Properties & Object Extension Manager Extra Properties system allows you to set/get dynamic properties to entities those implement the `IHasExtraProperties` interface. It is especially useful when you want to add custom properties to the entities defined in an [application module](Modules/Index.md), when you use the module as package reference. -By default, all the extra properties of an entity are stored as a single `JSON` object in the database. Entity extension system allows you to to store desired extra properties in separate fields in the related database table. +By default, all the extra properties of an entity are stored as a single `JSON` object in the database. -For more information about the extra properties & the entity extension system, see the following documents: +Entity extension system allows you to to store desired extra properties in separate fields in the related database table. For more information about the extra properties & the entity extension system, see the following documents: * [Customizing the Application Modules: Extending Entities](Customizing-Application-Modules-Extending-Entities.md) * [Entities](Entities.md) -This section only explains the `EntityExtensionManager` and its usage. +This section only explains the EF Core related usage of the `ObjectExtensionManager`. -### AddProperty Method +### ObjectExtensionManager.Instance -`AddProperty` method of the `EntityExtensionManager` allows you to define additional properties for an entity type. +`ObjectExtensionManager` implements the singleton pattern, so you need to use the static `ObjectExtensionManager.Instance` to perform all the operations. + +### MapEfCoreProperty + +`MapEfCoreProperty` is a shortcut extension method to define an extension property for an entity and map to the database. **Example**: Add `Title` property (database field) to the `IdentityRole` entity: ````csharp -EntityExtensionManager.AddProperty( - "Title", - b => { b.HasMaxLength(128); } -); +ObjectExtensionManager.Instance + .MapEfCoreProperty( + "Title", + builder => { builder.HasMaxLength(64); } + ); ```` -If the related module has implemented this feature (by using the `ConfigureExtensions` explained below), then the new property is added to the model. Then you need to run the standard `Add-Migration` and `Update-Database` commands to update your database to add the new field. +If the related module has implemented this feature (by using the `ConfigureEfCoreEntity` explained below), then the new property is added to the model. Then you need to run the standard `Add-Migration` and `Update-Database` commands to update your database to add the new field. ->`AddProperty` method must be called before using the related `DbContext`. It is a static method. The best way is to use it in your application as earlier as possible. The application startup template has a `YourProjectNameEntityExtensions` class that is safe to use this method inside. +>`MapEfCoreProperty` method must be called before using the related `DbContext`. It is a static method. The best way is to use it in your application as earlier as possible. The application startup template has a `YourProjectNameEntityExtensions` class that is safe to use this method inside. -### ConfigureExtensions +### ConfigureEfCoreEntity -If you are building a reusable module and want to allow application developers to add properties to your entities, you can use the `ConfigureExtensions` extension method in your entity mapping: +If you are building a reusable module and want to allow application developers to add properties to your entities, you can use the `ConfigureEfCoreEntity` extension method in your entity mapping. However, there is a shortcut extension method `ConfigureObjectExtensions` that can be used while configuring the entity mapping: ````csharp builder.Entity(b => { - b.ConfigureExtensions(); + b.ConfigureObjectExtensions(); //... }); ```` -If you call `ConfigureByConvention()` extension method (like `b.ConfigureByConvention()` in this example), ABP Framework internally calls the `ConfigureExtensions` method. It is a **best practice** to use the `ConfigureByConvention()` method since it also configures database mapping for base properties by convention. +> If you call `ConfigureByConvention()` extension method (like `b.ConfigureByConvention()` for this example), ABP Framework internally calls the `ConfigureObjectExtensions` method. It is a **best practice** to use the `ConfigureByConvention()` method since it also configures database mapping for base properties by convention. See the "*ConfigureByConvention Method*" section above for more information. -### GetPropertyNames - -`EntityExtensionManager.GetPropertyNames` static method can be used the names of the extension properties defined for this entity. It is normally not needed by an application code, but used by the ABP Framework internally. - ## Advanced Topics ### Set Default Repository Classes diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index dc5741e07f..91daadf350 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -11,7 +11,6 @@ namespace AutoMapper where TDestination : IHasExtraProperties where TSource : IHasExtraProperties { - var properties = ObjectExtensionManager.Instance.For().GetProperties(); return mappingExpression .ForMember( x => x.ExtraProperties, @@ -22,11 +21,15 @@ namespace AutoMapper ? new Dictionary() : new Dictionary(extraProps); - foreach (var property in properties) + var objectExtension = ObjectExtensionManager.Instance.GetOrNull(); + if (objectExtension != null) { - if (source.ExtraProperties.ContainsKey(property.Name)) + foreach (var property in objectExtension.GetProperties()) { - result[property.Name] = source.ExtraProperties[property.Name]; + if (source.ExtraProperties.ContainsKey(property.Name)) + { + result[property.Name] = source.ExtraProperties[property.Name]; + } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 2488ec9513..3ba7092395 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -18,11 +18,11 @@ using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Repositories; using Volo.Abp.EntityFrameworkCore.EntityHistory; -using Volo.Abp.EntityFrameworkCore.Extensions; using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; +using Volo.Abp.ObjectExtending; using Volo.Abp.Reflection; using Volo.Abp.Timing; using Volo.Abp.Uow; @@ -183,10 +183,18 @@ namespace Volo.Abp.EntityFrameworkCore return; } - var propertyNames = EntityExtensionManager.GetPropertyNames(entityType); + var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType); + if (objectExtension == null) + { + return; + } - foreach (var propertyName in propertyNames) + foreach (var property in objectExtension.GetProperties()) { + if (!property.IsMappedToFieldForEfCore()) + { + continue; + } /* Checking "currentValue != null" has a good advantage: * Assume that you we already using a named extra property, * then decided to create a field (entity extension) for it. @@ -194,10 +202,10 @@ namespace Volo.Abp.EntityFrameworkCore * updates the field on the next save! */ - var currentValue = e.Entry.CurrentValues[propertyName]; + var currentValue = e.Entry.CurrentValues[property.Name]; if (currentValue != null) { - entity.SetProperty(propertyName, currentValue); + entity.SetProperty(property.Name, currentValue); } } } @@ -251,12 +259,21 @@ namespace Volo.Abp.EntityFrameworkCore { return; } - - var propertyNames = EntityExtensionManager.GetPropertyNames(entityType); - foreach (var propertyName in propertyNames) + var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType); + if (objectExtension == null) + { + return; + } + + foreach (var property in objectExtension.GetProperties()) { - entry.Property(propertyName).CurrentValue = entity.GetProperty(propertyName); + if (!entity.HasProperty(property.Name)) + { + continue; + } + + entry.Property(property.Name).CurrentValue = entity.GetProperty(property.Name); } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionInfo.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionInfo.cs deleted file mode 100644 index f1aa105b9f..0000000000 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace Volo.Abp.EntityFrameworkCore.Extensions -{ - public class EntityExtensionInfo - { - public Dictionary Properties { get; set; } - - public EntityExtensionInfo() - { - Properties = new Dictionary(); - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionManager.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionManager.cs deleted file mode 100644 index d9f1ae9c31..0000000000 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/EntityExtensionManager.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Volo.Abp.Data; - -namespace Volo.Abp.EntityFrameworkCore.Extensions -{ - public static class EntityExtensionManager - { - private static readonly Dictionary ExtensionInfos; - - static EntityExtensionManager() - { - ExtensionInfos = new Dictionary(); - } - - /// - /// Adds an extension property for an entity. - /// If it is already added, replaces the - /// by the given one! - /// - /// Type of the entity - /// Type of the new property - /// Name of the property - /// An action to configure the database mapping for the new property - public static void AddProperty( - [NotNull]string propertyName, - [NotNull]Action propertyBuildAction) - { - AddProperty( - typeof(TEntity), - typeof(TProperty), - propertyName, - propertyBuildAction - ); - } - - /// - /// Adds an extension property for an entity. - /// If it is already added, replaces the - /// by the given one! - /// - /// Type of the entity - /// Type of the new property - /// Name of the property - /// An action to configure the database mapping for the new property - public static void AddProperty( - Type entityType, - Type propertyType, - [NotNull]string propertyName, - [NotNull]Action propertyBuildAction) - { - Check.NotNull(entityType, nameof(entityType)); - Check.NotNull(propertyType, nameof(propertyType)); - Check.NotNullOrWhiteSpace(propertyName, nameof(propertyName)); - Check.NotNull(propertyBuildAction, nameof(propertyBuildAction)); - - var extensionInfo = ExtensionInfos - .GetOrAdd(entityType, () => new EntityExtensionInfo()); - - var propertyExtensionInfo = extensionInfo.Properties - .GetOrAdd(propertyName, () => new PropertyExtensionInfo(propertyType)); - - propertyExtensionInfo.Action = propertyBuildAction; - } - - /// - /// Configures the entity mapping for the defined extensions. - /// - /// The entity tye - /// Entity type builder - public static void ConfigureExtensions( - [NotNull] this EntityTypeBuilder entityTypeBuilder) - where TEntity : class, IHasExtraProperties - { - ConfigureExtensions(typeof(TEntity), entityTypeBuilder); - } - - /// - /// Configures the entity mapping for the defined extensions. - /// - /// Type of the entity - /// Entity type builder - public static void ConfigureExtensions( - [NotNull] Type entityType, - [NotNull] EntityTypeBuilder entityTypeBuilder) - { - Check.NotNull(entityType, nameof(entityType)); - Check.NotNull(entityTypeBuilder, nameof(entityTypeBuilder)); - - var entityExtensionInfo = ExtensionInfos.GetOrDefault(entityType); - if (entityExtensionInfo == null) - { - return; - } - - foreach (var propertyExtensionInfo in entityExtensionInfo.Properties) - { - var propertyName = propertyExtensionInfo.Key; - var propertyType = propertyExtensionInfo.Value.PropertyType; - - /* Prevent multiple calls to the entityTypeBuilder.Property(...) method */ - if (entityTypeBuilder.Metadata.FindProperty(propertyName) != null) - { - continue; - } - - var property = entityTypeBuilder.Property( - propertyType, - propertyName - ); - - propertyExtensionInfo.Value.Action(property); - } - } - - public static string[] GetPropertyNames(Type entityType) - { - var entityExtensionInfo = ExtensionInfos.GetOrDefault(entityType); - if (entityExtensionInfo == null) - { - return Array.Empty(); - } - - return entityExtensionInfo - .Properties - .Select(p => p.Key) - .ToArray(); - } - } -} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/PropertyExtensionInfo.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/PropertyExtensionInfo.cs deleted file mode 100644 index df29bdd62d..0000000000 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Extensions/PropertyExtensionInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Volo.Abp.EntityFrameworkCore.Extensions -{ - public class PropertyExtensionInfo - { - public Action Action { get; set; } - - public Type PropertyType { get; } - - public PropertyExtensionInfo(Type propertyType) - { - PropertyType = propertyType; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs index eca8831e35..b64866f8be 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs @@ -5,10 +5,10 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; -using Volo.Abp.EntityFrameworkCore.Extensions; using Volo.Abp.EntityFrameworkCore.ValueComparers; using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.MultiTenancy; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.EntityFrameworkCore.Modeling { @@ -18,6 +18,7 @@ namespace Volo.Abp.EntityFrameworkCore.Modeling { b.TryConfigureConcurrencyStamp(); b.TryConfigureExtraProperties(); + b.TryConfigureObjectExtensions(); b.TryConfigureMayHaveCreator(); b.TryConfigureMustHaveCreator(); b.TryConfigureSoftDelete(); @@ -54,16 +55,28 @@ namespace Volo.Abp.EntityFrameworkCore.Modeling public static void TryConfigureExtraProperties(this EntityTypeBuilder b) { - //TODO: Max length? - if (b.Metadata.ClrType.IsAssignableTo()) + if (!b.Metadata.ClrType.IsAssignableTo()) { - b.Property>(nameof(IHasExtraProperties.ExtraProperties)) - .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)) - .HasConversion(new ExtraPropertiesValueConverter(b.Metadata.ClrType)) - .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); - - EntityExtensionManager.ConfigureExtensions(b.Metadata.ClrType, b); + return; } + + b.Property>(nameof(IHasExtraProperties.ExtraProperties)) + .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)) + .HasConversion(new ExtraPropertiesValueConverter(b.Metadata.ClrType)) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); + + b.TryConfigureObjectExtensions(); + } + + public static void ConfigureObjectExtensions(this EntityTypeBuilder b) + where T : class + { + b.As().TryConfigureObjectExtensions(); + } + + public static void TryConfigureObjectExtensions(this EntityTypeBuilder b) + { + ObjectExtensionManager.Instance.ConfigureEfCoreEntity(b); } public static void ConfigureSoftDelete(this EntityTypeBuilder b) @@ -286,7 +299,6 @@ namespace Volo.Abp.EntityFrameworkCore.Modeling b.As().TryConfigureConcurrencyStamp(); } - //TODO: Add other interfaces (IAuditedObject...) } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs index fb1abf0e24..ddcdb942ba 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/ExtraPropertiesValueConverter.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Newtonsoft.Json; -using Volo.Abp.EntityFrameworkCore.Extensions; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.EntityFrameworkCore.ValueConverters { @@ -22,11 +22,16 @@ namespace Volo.Abp.EntityFrameworkCore.ValueConverters if (entityType != null) { - var propertyNames = EntityExtensionManager.GetPropertyNames(entityType); - - foreach (var propertyName in propertyNames) + var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType); + if (objectExtension != null) { - copyDictionary.Remove(propertyName); + foreach (var property in objectExtension.GetProperties()) + { + if (property.IsMappedToFieldForEfCore()) + { + copyDictionary.Remove(property.Name); + } + } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs new file mode 100644 index 0000000000..783edf8b8b --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Volo.Abp.ObjectExtending +{ + public static class EfCoreObjectExtensionInfoExtensions + { + public static ObjectExtensionPropertyInfo MapEfCoreProperty( + this ObjectExtensionInfo objectExtensionInfo, + string propertyName, + Action propertyBuildAction) + { + return objectExtensionInfo.MapEfCoreProperty( + typeof(TDbField), + propertyName, + propertyBuildAction + ); + } + + public static ObjectExtensionPropertyInfo MapEfCoreProperty( + this ObjectExtensionInfo objectExtensionInfo, + Type dbFieldType, + string propertyName, + Action propertyBuildAction) + { + return objectExtensionInfo.AddOrUpdateProperty( + propertyName, + options => + { + options.MapEfCore( + dbFieldType, + propertyBuildAction + ); + }); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs new file mode 100644 index 0000000000..9261bdc3e8 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs @@ -0,0 +1,75 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Volo.Abp.ObjectExtending +{ + public static class EfCoreObjectExtensionManagerExtensions + { + public static ObjectExtensionInfo MapEfCoreProperty( + this ObjectExtensionManager objectExtensionManager, + string propertyName, + Action propertyBuildAction) + { + return objectExtensionManager.MapEfCoreProperty( + typeof(TObject), + typeof(TDbField), + propertyName, + propertyBuildAction + ); + } + + public static ObjectExtensionInfo MapEfCoreProperty( + this ObjectExtensionManager objectExtensionManager, + Type objectType, + Type dbFieldType, + string propertyName, + Action propertyBuildAction) + { + return objectExtensionManager.AddOrUpdate( + objectType, + objectOptions => + { + objectOptions.AddOrUpdateProperty( + propertyName, + propertyOptions => + { + propertyOptions.MapEfCore( + dbFieldType, + propertyBuildAction + ); + } + ); + }); + } + + public static void ConfigureEfCoreEntity( + this ObjectExtensionManager objectExtensionManager, + EntityTypeBuilder b) + { + var objectExtension = objectExtensionManager.GetOrNull(b.Metadata.ClrType); + if (objectExtension == null) + { + return; + } + + foreach (var property in objectExtension.GetProperties()) + { + var efCoreMapping = property.GetEfCoreMappingOrNull(); + if (efCoreMapping == null) + { + continue; + } + + /* Prevent multiple calls to the entityTypeBuilder.Property(...) method */ + if (b.Metadata.FindProperty(property.Name) != null) + { + continue; + } + + var propertyBuilder = b.Property(efCoreMapping.FieldType, property.Name); + + efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder); + } + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs new file mode 100644 index 0000000000..9f97d0d7f4 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Volo.Abp.ObjectExtending +{ + public static class EfCoreObjectExtensionPropertyInfoExtensions + { + public const string EfCorePropertyConfigurationName = "EfCoreMapping"; + + public static ObjectExtensionPropertyInfo MapEfCore( + this ObjectExtensionPropertyInfo propertyExtension, + Type dbFieldType, + Action propertyBuildAction) + { + var options = new ObjectExtensionPropertyInfoEfCoreMappingOptions( + dbFieldType, + propertyExtension, + propertyBuildAction + ); + + propertyExtension.Configuration[EfCorePropertyConfigurationName] = options; + + return propertyExtension; + } + + [CanBeNull] + public static ObjectExtensionPropertyInfoEfCoreMappingOptions GetEfCoreMappingOrNull( + this ObjectExtensionPropertyInfo propertyExtension) + { + return propertyExtension.Configuration.GetOrDefault(EfCorePropertyConfigurationName) + as ObjectExtensionPropertyInfoEfCoreMappingOptions; + } + + public static bool IsMappedToFieldForEfCore(this ObjectExtensionPropertyInfo propertyExtension) + { + return propertyExtension.Configuration.ContainsKey(EfCorePropertyConfigurationName); + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs new file mode 100644 index 0000000000..20dd1cef0a --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs @@ -0,0 +1,31 @@ +using System; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Volo.Abp.ObjectExtending +{ + public class ObjectExtensionPropertyInfoEfCoreMappingOptions + { + [NotNull] + public ObjectExtensionPropertyInfo ExtensionProperty { get; } + + [NotNull] + public ObjectExtensionInfo ObjectExtension => ExtensionProperty.ObjectExtension; + + [NotNull] + public Type FieldType { get; } + + [CanBeNull] + public Action PropertyBuildAction { get; set; } + + public ObjectExtensionPropertyInfoEfCoreMappingOptions( + [NotNull] Type fieldType, + [NotNull] ObjectExtensionPropertyInfo extensionProperty, + [CanBeNull] Action propertyBuildAction = null) + { + FieldType = Check.NotNull(fieldType, nameof(fieldType)); + ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty)); + PropertyBuildAction = propertyBuildAction; + } + } +} \ 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 86e288c932..3f415172e2 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.ObjectExtending where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { - var extensionPropertyInfos = ObjectExtensionManager.Instance.For().GetProperties(); + var extensionPropertyInfos = ObjectExtensionManager.Instance.AddOrUpdate().GetProperties(); foreach (var extensionPropertyInfo in extensionPropertyInfos) { diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index 04698c6b69..ffe1c8b03c 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -19,13 +19,13 @@ namespace Volo.Abp.ObjectExtending Configuration = new Dictionary(); } - public ObjectExtensionPropertyInfo AddProperty( + public ObjectExtensionPropertyInfo AddOrUpdateProperty( string propertyName, Action configureAction = null) { var propertyInfo = Properties.GetOrAdd( propertyName, - () => new ObjectExtensionPropertyInfo(propertyName) + () => new ObjectExtensionPropertyInfo(this, propertyName) ); configureAction?.Invoke(propertyInfo); diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs index ad820522f2..d6a42e82c7 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -5,26 +5,43 @@ namespace Volo.Abp.ObjectExtending { public class ObjectExtensionManager { - public static ObjectExtensionManager Instance { get; } = new ObjectExtensionManager(); + public static ObjectExtensionManager Instance { get; set; } = new ObjectExtensionManager(); - private Dictionary ObjectsExtensions { get; } + protected Dictionary ObjectsExtensions { get; } - private ObjectExtensionManager() + protected ObjectExtensionManager() { ObjectsExtensions = new Dictionary(); } - public ObjectExtensionInfo For( + public virtual ObjectExtensionInfo AddOrUpdate( + Action configureAction = null) + { + return AddOrUpdate(typeof(TObject), configureAction); + } + + public virtual ObjectExtensionInfo AddOrUpdate( + Type type, Action configureAction = null) { var extensionInfo = ObjectsExtensions.GetOrAdd( - typeof(TObject), - () => new ObjectExtensionInfo(typeof(TObject)) + type, + () => new ObjectExtensionInfo(type) ); configureAction?.Invoke(extensionInfo); return extensionInfo; } + + public virtual ObjectExtensionInfo GetOrNull() + { + return GetOrNull(typeof(TObject)); + } + + public virtual ObjectExtensionInfo GetOrNull(Type type) + { + return ObjectsExtensions.GetOrDefault(type); + } } } \ 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 981bfd3040..baac9962fa 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -1,19 +1,28 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using JetBrains.Annotations; namespace Volo.Abp.ObjectExtending { public class ObjectExtensionPropertyInfo { + [NotNull] + public ObjectExtensionInfo ObjectExtension { get; } + + [NotNull] public string Name { get; } + [NotNull] public List ValidationAttributes { get; } + [NotNull] public Dictionary Configuration { get; } - public ObjectExtensionPropertyInfo(string name) + public ObjectExtensionPropertyInfo(ObjectExtensionInfo objectExtension, string name) { - Name = name; + ObjectExtension = Check.NotNull(objectExtension, nameof(objectExtension)); + Name = Check.NotNull(name, nameof(name)); + ValidationAttributes = new List(); Configuration = new Dictionary(); } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/TestEntityExtensionConfigurator.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/TestEntityExtensionConfigurator.cs index 2ae6888e7f..3d415d79e6 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/TestEntityExtensionConfigurator.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Domain/TestEntityExtensionConfigurator.cs @@ -1,4 +1,4 @@ -using Volo.Abp.EntityFrameworkCore.Extensions; +using Volo.Abp.ObjectExtending; using Volo.Abp.TestApp.Domain; using Volo.Abp.Threading; @@ -12,10 +12,11 @@ namespace Volo.Abp.EntityFrameworkCore.Domain { OneTimeRunner.Run(() => { - EntityExtensionManager.AddProperty( - "PhoneCode", - p => p.HasMaxLength(8) - ); + ObjectExtensionManager.Instance + .MapEfCoreProperty( + "PhoneCode", + p => p.HasMaxLength(8) + ); }); } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs index 6293e21716..da66392a18 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore.Extensions; using Volo.Abp.EntityFrameworkCore.TestApp.SecondContext; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; @@ -37,8 +36,6 @@ namespace Volo.Abp.EntityFrameworkCore modelBuilder.Entity(b => { - //b.ConfigureExtensions(); - b.OwnsMany(c => c.Districts, d => { d.WithOwner().HasForeignKey(x => x.CityId); diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs index 3bc1678764..289364411d 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs @@ -1,6 +1,5 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore.Extensions; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; @@ -44,8 +43,6 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore modelBuilder.Entity(b => { - //b.ConfigureExtensions(); - b.OwnsMany(c => c.Districts, d => { d.WithOwner().HasForeignKey(x => x.CityId); diff --git a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs index c5176755d1..05b99e767e 100644 --- a/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs +++ b/modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/IdentityDbContextModelBuilderExtensions.cs @@ -1,7 +1,6 @@ using System; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore.Extensions; using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.Users.EntityFrameworkCore; From 61453a2bd39010b6d2d68d42e6dd1caee5132a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 18:00:33 +0300 Subject: [PATCH 08/24] Update template for the ObjectExtending change. --- .../MyProjectNameEntityExtensions.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameEntityExtensions.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameEntityExtensions.cs index 2e36827403..af1076ebda 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameEntityExtensions.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore/EntityFrameworkCore/MyProjectNameEntityExtensions.cs @@ -1,5 +1,5 @@ -using Volo.Abp.EntityFrameworkCore.Extensions; -using Volo.Abp.Identity; +using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; using Volo.Abp.Threading; namespace MyCompanyName.MyProjectName.EntityFrameworkCore @@ -17,12 +17,11 @@ namespace MyCompanyName.MyProjectName.EntityFrameworkCore * * Example: * - * EntityExtensionManager.AddProperty( - * "MyProperty", - * b => - * { - * b.HasMaxLength(128); - * }); + * ObjectExtensionManager.Instance + * .MapEfCoreProperty( + * "MyProperty", + * b => b.HasMaxLength(128) + * ); * * See the documentation for more: * https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities From b6a92c0e00d4727eb46b9f089a0c623bfac83dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 18:16:50 +0300 Subject: [PATCH 09/24] Apply object extensions for identity role app service. --- .../Abp/Identity/IIdentityRoleAppService.cs | 1 - .../IdentityRoleCreateOrUpdateDtoBase.cs | 3 ++- .../Volo/Abp/Identity/IdentityRoleDto.cs | 4 ++-- ...ntityApplicationModuleAutoMapperProfile.cs | 5 ++++- .../Abp/Identity/IdentityRoleAppService.cs | 22 ++++++++++++++----- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs index 9381a9b2c8..36f483d0e6 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IIdentityRoleAppService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs index c335c3c338..8e11d89b30 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleCreateOrUpdateDtoBase.cs @@ -1,8 +1,9 @@ using System.ComponentModel.DataAnnotations; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Identity { - public class IdentityRoleCreateOrUpdateDtoBase + public class IdentityRoleCreateOrUpdateDtoBase : ExtensibleObject { [Required] [StringLength(IdentityRoleConsts.MaxNameLength)] diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs index d55b68fcb1..ae5d8a5feb 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityRoleDto.cs @@ -4,12 +4,12 @@ using Volo.Abp.Domain.Entities; namespace Volo.Abp.Identity { - public class IdentityRoleDto : EntityDto, IHasConcurrencyStamp + public class IdentityRoleDto : ExtensibleEntityDto, IHasConcurrencyStamp { public string Name { get; set; } public bool IsDefault { get; set; } - + public bool IsStatic { get; set; } public bool IsPublic { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs index d3886a334c..7910ff6dcb 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs @@ -7,7 +7,10 @@ namespace Volo.Abp.Identity public AbpIdentityApplicationModuleAutoMapperProfile() { CreateMap(); - CreateMap(); + + CreateMap() + .MapExtraProperties(); + CreateMap(); } } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs index 02d5f990f5..051251a70a 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityRoleAppService.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Volo.Abp.Application.Dtos; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Identity { @@ -24,14 +25,16 @@ namespace Volo.Abp.Identity public virtual async Task GetAsync(Guid id) { return ObjectMapper.Map( - await RoleManager.GetByIdAsync(id)); + await RoleManager.GetByIdAsync(id) + ); } public virtual async Task> GetAllListAsync() { var list = await RoleRepository.GetListAsync(); return new ListResultDto( - ObjectMapper.Map, List>(list)); + ObjectMapper.Map, List>(list) + ); } public virtual async Task> GetListAsync(PagedAndSortedResultRequestDto input) @@ -48,10 +51,17 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Roles.Create)] public virtual async Task CreateAsync(IdentityRoleCreateDto input) { - var role = new IdentityRole(GuidGenerator.Create(), input.Name, CurrentTenant.Id); + var role = new IdentityRole( + GuidGenerator.Create(), + input.Name, + CurrentTenant.Id + ) + { + IsDefault = input.IsDefault, + IsPublic = input.IsPublic + }; - role.IsDefault = input.IsDefault; - role.IsPublic = input.IsPublic; + input.MapExtraPropertiesTo(role); (await RoleManager.CreateAsync(role)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); @@ -70,6 +80,8 @@ namespace Volo.Abp.Identity role.IsDefault = input.IsDefault; role.IsPublic = input.IsPublic; + input.MapExtraPropertiesTo(role); + (await RoleManager.UpdateAsync(role)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); From 4cab2214f57751238b6ff92e17c03cae0303f984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 18:28:42 +0300 Subject: [PATCH 10/24] Implement object extensions for the identity module. --- .../IdentityUserCreateOrUpdateDtoBase.cs | 3 ++- .../Volo/Abp/Identity/IdentityUserDto.cs | 2 +- .../Volo/Abp/Identity/ProfileDto.cs | 6 ++++-- .../Volo/Abp/Identity/UpdateProfileDto.cs | 3 ++- ...IdentityApplicationModuleAutoMapperProfile.cs | 8 +++++--- .../Volo/Abp/Identity/IdentityUserAppService.cs | 16 ++++++++++++++-- .../Volo/Abp/Identity/ProfileAppService.cs | 3 +++ 7 files changed, 31 insertions(+), 10 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs index 0715d2512a..ec8b4ef213 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserCreateOrUpdateDtoBase.cs @@ -1,9 +1,10 @@ using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Identity { - public abstract class IdentityUserCreateOrUpdateDtoBase + public abstract class IdentityUserCreateOrUpdateDtoBase : ExtensibleObject { [Required] [StringLength(IdentityUserConsts.MaxUserNameLength)] diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs index 02d1b10166..9f94d7b599 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/IdentityUserDto.cs @@ -5,7 +5,7 @@ using Volo.Abp.MultiTenancy; namespace Volo.Abp.Identity { - public class IdentityUserDto : FullAuditedEntityDto, IMultiTenant, IHasConcurrencyStamp + public class IdentityUserDto : ExtensibleFullAuditedEntityDto, IMultiTenant, IHasConcurrencyStamp { public Guid? TenantId { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs index ac9b09e287..4777c0ad23 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/ProfileDto.cs @@ -1,6 +1,8 @@ -namespace Volo.Abp.Identity +using Volo.Abp.ObjectExtending; + +namespace Volo.Abp.Identity { - public class ProfileDto + public class ProfileDto : ExtensibleObject { public string UserName { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs index 40a576f871..52919c7744 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application.Contracts/Volo/Abp/Identity/UpdateProfileDto.cs @@ -1,8 +1,9 @@ using System.ComponentModel.DataAnnotations; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Identity { - public class UpdateProfileDto + public class UpdateProfileDto : ExtensibleObject { [StringLength(IdentityUserConsts.MaxUserNameLength)] public string UserName { get; set; } diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs index 7910ff6dcb..01a68dc677 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/AbpIdentityApplicationModuleAutoMapperProfile.cs @@ -6,12 +6,14 @@ namespace Volo.Abp.Identity { public AbpIdentityApplicationModuleAutoMapperProfile() { - CreateMap(); - + CreateMap() + .MapExtraProperties(); + CreateMap() .MapExtraProperties(); - CreateMap(); + CreateMap() + .MapExtraProperties(); } } } \ No newline at end of file diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index 71adeef1b0..9d231b18d1 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Volo.Abp.Application.Dtos; +using Volo.Abp.ObjectExtending; namespace Volo.Abp.Identity { @@ -45,6 +46,7 @@ namespace Volo.Abp.Identity public virtual async Task> GetRolesAsync(Guid id) { var roles = await UserRepository.GetRolesAsync(id); + return new ListResultDto( ObjectMapper.Map, List>(roles) ); @@ -53,7 +55,14 @@ namespace Volo.Abp.Identity [Authorize(IdentityPermissions.Users.Create)] public virtual async Task CreateAsync(IdentityUserCreateDto input) { - var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.Email, CurrentTenant.Id); + var user = new IdentityUser( + GuidGenerator.Create(), + input.UserName, + input.Email, + CurrentTenant.Id + ); + + input.MapExtraPropertiesTo(user); (await UserManager.CreateAsync(user, input.Password)).CheckErrors(); await UpdateUserByInput(user, input); @@ -70,7 +79,10 @@ namespace Volo.Abp.Identity user.ConcurrencyStamp = input.ConcurrencyStamp; (await UserManager.SetUserNameAsync(user, input.UserName)).CheckErrors(); + await UpdateUserByInput(user, input); + input.MapExtraPropertiesTo(user); + (await UserManager.UpdateAsync(user)).CheckErrors(); if (!input.Password.IsNullOrEmpty()) @@ -78,7 +90,7 @@ namespace Volo.Abp.Identity (await UserManager.RemovePasswordAsync(user)).CheckErrors(); (await UserManager.AddPasswordAsync(user, input.Password)).CheckErrors(); } - + await CurrentUnitOfWork.SaveChangesAsync(); return ObjectMapper.Map(user); diff --git a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs index 7501108dec..45bcdf3e35 100644 --- a/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs +++ b/modules/identity/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/ProfileAppService.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Volo.Abp.Identity.Settings; +using Volo.Abp.ObjectExtending; using Volo.Abp.Settings; using Volo.Abp.Users; @@ -43,6 +44,8 @@ namespace Volo.Abp.Identity user.Name = input.Name; user.Surname = input.Surname; + input.MapExtraPropertiesTo(user); + (await UserManager.UpdateAsync(user)).CheckErrors(); await CurrentUnitOfWork.SaveChangesAsync(); From ea984ba458446d2be17aad553f323b0b8cc7c929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 18:37:24 +0300 Subject: [PATCH 11/24] Temporary disable ValidationAttributes --- .../Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 baac9962fa..58879cfd59 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -12,8 +12,8 @@ namespace Volo.Abp.ObjectExtending [NotNull] public string Name { get; } - [NotNull] - public List ValidationAttributes { get; } + //[NotNull] //TODO: Will be implemented, probably in the v2.5 + //public List ValidationAttributes { get; } [NotNull] public Dictionary Configuration { get; } @@ -23,7 +23,7 @@ namespace Volo.Abp.ObjectExtending ObjectExtension = Check.NotNull(objectExtension, nameof(objectExtension)); Name = Check.NotNull(name, nameof(name)); - ValidationAttributes = new List(); + //ValidationAttributes = new List(); Configuration = new Dictionary(); } } From fd77eeefedabbcda643ed071830a3e3eab7121f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 18:37:38 +0300 Subject: [PATCH 12/24] add HasProperty --- .../AbpAutoMapperExtensibleDtoExtensions.cs | 1 + .../Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index 91daadf350..e277fbf202 100644 --- a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs +++ b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs @@ -22,6 +22,7 @@ namespace AutoMapper : new Dictionary(extraProps); var objectExtension = ObjectExtensionManager.Instance.GetOrNull(); + if (objectExtension != null) { foreach (var property in objectExtension.GetProperties()) diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index ffe1c8b03c..19f53c4b75 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.ObjectExtending { public Type Type { get; } - public Dictionary Properties { get; } + protected Dictionary Properties { get; } public Dictionary Configuration { get; } @@ -19,7 +19,12 @@ namespace Volo.Abp.ObjectExtending Configuration = new Dictionary(); } - public ObjectExtensionPropertyInfo AddOrUpdateProperty( + public virtual bool HasProperty(string propertyName) + { + return Properties.ContainsKey(propertyName); + } + + public virtual ObjectExtensionPropertyInfo AddOrUpdateProperty( string propertyName, Action configureAction = null) { @@ -33,7 +38,7 @@ namespace Volo.Abp.ObjectExtending return propertyInfo; } - public ImmutableList GetProperties() + public virtual ImmutableList GetProperties() { return Properties.Values.ToImmutableList(); } From ff55b9f83fd00cb764454d8291cd59881e3041f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 21:16:26 +0300 Subject: [PATCH 13/24] Added MappingPropertyDefinitionCheck. --- ...xtraPropertiesObjectExtendingExtensions.cs | 87 +++++++++++++++++-- .../MappingPropertyDefinitionCheck.cs | 28 ++++++ 2 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs 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 3f415172e2..4226bb30f7 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -1,22 +1,97 @@ -using Volo.Abp.Data; +using System; +using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending { public static class HasExtraPropertiesObjectExtendingExtensions { - public static void MapExtraPropertiesTo(this TSource source, TDestination destination) + /// + /// Copies extra properties from the object + /// to the object. + /// + /// Checks property definitions (over the ) + /// based on the preference. + /// + /// + /// + /// The source object + /// The destination object + /// + /// Controls which properties to map. + /// + public static void MapExtraPropertiesTo( + this TSource source, + TDestination destination, + MappingPropertyDefinitionCheck definitionCheck = MappingPropertyDefinitionCheck.Both) where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { - var extensionPropertyInfos = ObjectExtensionManager.Instance.AddOrUpdate().GetProperties(); + var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); + if (definitionCheck.HasFlag(MappingPropertyDefinitionCheck.Source) && + sourceObjectExtension == null) + { + return; + } + + var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); + if (definitionCheck.HasFlag(MappingPropertyDefinitionCheck.Destination) && + destinationObjectExtension == null) + { + return; + } - foreach (var extensionPropertyInfo in extensionPropertyInfos) + if (definitionCheck == MappingPropertyDefinitionCheck.None) + { + foreach (var keyValue in source.ExtraProperties) + { + destination.ExtraProperties[keyValue.Key] = keyValue.Value; + } + } + else if (definitionCheck == MappingPropertyDefinitionCheck.Source) { - if (source.ExtraProperties.ContainsKey(extensionPropertyInfo.Name)) + foreach (var property in sourceObjectExtension.GetProperties()) { - destination.ExtraProperties[extensionPropertyInfo.Name] = source.ExtraProperties[extensionPropertyInfo.Name]; + if (!source.ExtraProperties.ContainsKey(property.Name)) + { + continue; + } + + destination.ExtraProperties[property.Name] = source.ExtraProperties[property.Name]; } } + else if (definitionCheck == MappingPropertyDefinitionCheck.Destination) + { + foreach (var keyValue in source.ExtraProperties) + { + if (!destinationObjectExtension.HasProperty(keyValue.Key)) + { + continue; + } + + destination.ExtraProperties[keyValue.Key] = keyValue.Value; + } + } + else if(definitionCheck == MappingPropertyDefinitionCheck.Both) + { + foreach (var property in sourceObjectExtension.GetProperties()) + { + if (!source.ExtraProperties.ContainsKey(property.Name)) + { + continue; + } + + if (!destinationObjectExtension.HasProperty(property.Name)) + { + continue; + } + + destination.ExtraProperties[property.Name] = source.ExtraProperties[property.Name]; + } + } + else + { + throw new NotImplementedException(definitionCheck + " was not implemented!"); + } } } } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs new file mode 100644 index 0000000000..f1bd9c3c66 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs @@ -0,0 +1,28 @@ +using System; + +namespace Volo.Abp.ObjectExtending +{ + [Flags] + public enum MappingPropertyDefinitionCheck : byte + { + /// + /// No check. Copy all extra properties from the source to the destination. + /// + None = 0, + + /// + /// Copy the extra properties defined for the source class. + /// + Source = 1, + + /// + /// Copy the extra properties defined for the destination class. + /// + Destination = 2, + + /// + /// Copy extra properties defined for both of the source and destination classes. + /// + Both = Source | Destination + } +} \ No newline at end of file From 1c564b10dfdcadb3bc2d2051f0a5e30225235338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 23:26:03 +0300 Subject: [PATCH 14/24] Require property type when creating an extension property. Also added ObjectExtensionManagerExtensions --- .../EfCoreObjectExtensionInfoExtensions.cs | 28 ++++---- .../EfCoreObjectExtensionManagerExtensions.cs | 72 +++++++++---------- ...reObjectExtensionPropertyInfoExtensions.cs | 17 +++-- ...tensionPropertyInfoEfCoreMappingOptions.cs | 5 -- .../ObjectExtending/ObjectExtensionInfo.cs | 26 +++++-- .../ObjectExtending/ObjectExtensionManager.cs | 21 ++++-- .../ObjectExtensionManagerExtensions.cs | 44 ++++++++++++ .../ObjectExtensionPropertyInfo.cs | 10 ++- 8 files changed, 145 insertions(+), 78 deletions(-) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManagerExtensions.cs diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs index 783edf8b8b..ef3d87119a 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionInfoExtensions.cs @@ -1,37 +1,41 @@ using System; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Volo.Abp.ObjectExtending { public static class EfCoreObjectExtensionInfoExtensions { - public static ObjectExtensionPropertyInfo MapEfCoreProperty( - this ObjectExtensionInfo objectExtensionInfo, - string propertyName, - Action propertyBuildAction) + public static ObjectExtensionInfo MapEfCoreProperty( + [NotNull] this ObjectExtensionInfo objectExtensionInfo, + [NotNull] string propertyName, + [CanBeNull] Action propertyBuildAction) { return objectExtensionInfo.MapEfCoreProperty( - typeof(TDbField), + typeof(TProperty), propertyName, propertyBuildAction ); } - public static ObjectExtensionPropertyInfo MapEfCoreProperty( - this ObjectExtensionInfo objectExtensionInfo, - Type dbFieldType, - string propertyName, - Action propertyBuildAction) + public static ObjectExtensionInfo MapEfCoreProperty( + [NotNull] this ObjectExtensionInfo objectExtensionInfo, + [NotNull] Type propertyType, + [NotNull] string propertyName, + [CanBeNull] Action propertyBuildAction) { + Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo)); + return objectExtensionInfo.AddOrUpdateProperty( + propertyType, propertyName, options => { options.MapEfCore( - dbFieldType, propertyBuildAction ); - }); + } + ); } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs index 9261bdc3e8..a7c392f7c4 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs @@ -1,75 +1,73 @@ using System; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending { public static class EfCoreObjectExtensionManagerExtensions { - public static ObjectExtensionInfo MapEfCoreProperty( + public static ObjectExtensionManager MapEfCoreProperty( this ObjectExtensionManager objectExtensionManager, string propertyName, Action propertyBuildAction) + where TObject : IHasExtraProperties { return objectExtensionManager.MapEfCoreProperty( typeof(TObject), - typeof(TDbField), + typeof(TProperty), propertyName, propertyBuildAction ); } - public static ObjectExtensionInfo MapEfCoreProperty( + public static ObjectExtensionManager MapEfCoreProperty( this ObjectExtensionManager objectExtensionManager, Type objectType, - Type dbFieldType, + Type propertyType, string propertyName, Action propertyBuildAction) { - return objectExtensionManager.AddOrUpdate( + return objectExtensionManager.AddOrUpdateProperty( objectType, - objectOptions => + propertyType, + propertyName, + options => { - objectOptions.AddOrUpdateProperty( - propertyName, - propertyOptions => - { - propertyOptions.MapEfCore( - dbFieldType, - propertyBuildAction - ); - } + options.MapEfCore( + propertyBuildAction ); - }); + } + ); } - public static void ConfigureEfCoreEntity( - this ObjectExtensionManager objectExtensionManager, - EntityTypeBuilder b) + public static void ConfigureEfCoreEntity( + this ObjectExtensionManager objectExtensionManager, + EntityTypeBuilder b) + { + var objectExtension = objectExtensionManager.GetOrNull(b.Metadata.ClrType); + if (objectExtension == null) + { + return; + } + + foreach (var property in objectExtension.GetProperties()) { - var objectExtension = objectExtensionManager.GetOrNull(b.Metadata.ClrType); - if (objectExtension == null) + var efCoreMapping = property.GetEfCoreMappingOrNull(); + if (efCoreMapping == null) { - return; + continue; } - foreach (var property in objectExtension.GetProperties()) + /* Prevent multiple calls to the entityTypeBuilder.Property(...) method */ + if (b.Metadata.FindProperty(property.Name) != null) { - var efCoreMapping = property.GetEfCoreMappingOrNull(); - if (efCoreMapping == null) - { - continue; - } - - /* Prevent multiple calls to the entityTypeBuilder.Property(...) method */ - if (b.Metadata.FindProperty(property.Name) != null) - { - continue; - } + continue; + } - var propertyBuilder = b.Property(efCoreMapping.FieldType, property.Name); + var propertyBuilder = b.Property(property.Type, property.Name); - efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder); - } + efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder); } } } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs index 9f97d0d7f4..e76edb167a 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs @@ -10,17 +10,16 @@ namespace Volo.Abp.ObjectExtending public const string EfCorePropertyConfigurationName = "EfCoreMapping"; public static ObjectExtensionPropertyInfo MapEfCore( - this ObjectExtensionPropertyInfo propertyExtension, - Type dbFieldType, - Action propertyBuildAction) + [NotNull] this ObjectExtensionPropertyInfo propertyExtension, + [CanBeNull] Action propertyBuildAction = null) { - var options = new ObjectExtensionPropertyInfoEfCoreMappingOptions( - dbFieldType, - propertyExtension, - propertyBuildAction - ); + Check.NotNull(propertyExtension, nameof(propertyExtension)); - propertyExtension.Configuration[EfCorePropertyConfigurationName] = options; + propertyExtension.Configuration[EfCorePropertyConfigurationName] = + new ObjectExtensionPropertyInfoEfCoreMappingOptions( + propertyExtension, + propertyBuildAction + ); return propertyExtension; } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs index 20dd1cef0a..0c9909f5d7 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs @@ -12,18 +12,13 @@ namespace Volo.Abp.ObjectExtending [NotNull] public ObjectExtensionInfo ObjectExtension => ExtensionProperty.ObjectExtension; - [NotNull] - public Type FieldType { get; } - [CanBeNull] public Action PropertyBuildAction { get; set; } public ObjectExtensionPropertyInfoEfCoreMappingOptions( - [NotNull] Type fieldType, [NotNull] ObjectExtensionPropertyInfo extensionProperty, [CanBeNull] Action propertyBuildAction = null) { - FieldType = Check.NotNull(fieldType, nameof(fieldType)); ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty)); PropertyBuildAction = propertyBuildAction; } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index 19f53c4b75..6f59465660 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using JetBrains.Annotations; namespace Volo.Abp.ObjectExtending { @@ -24,18 +25,33 @@ namespace Volo.Abp.ObjectExtending return Properties.ContainsKey(propertyName); } - public virtual ObjectExtensionPropertyInfo AddOrUpdateProperty( - string propertyName, - Action configureAction = null) + public virtual ObjectExtensionInfo AddOrUpdateProperty( + [NotNull] string propertyName, + [CanBeNull] Action configureAction = null) { + return AddOrUpdateProperty( + typeof(TProperty), + propertyName, + configureAction + ); + } + + public virtual ObjectExtensionInfo AddOrUpdateProperty( + [NotNull] Type propertyType, + [NotNull] string propertyName, + [CanBeNull] Action configureAction = null) + { + Check.NotNull(propertyType, nameof(propertyType)); + Check.NotNull(propertyName, nameof(propertyName)); + var propertyInfo = Properties.GetOrAdd( propertyName, - () => new ObjectExtensionPropertyInfo(this, propertyName) + () => new ObjectExtensionPropertyInfo(this, propertyType, propertyName) ); configureAction?.Invoke(propertyInfo); - return propertyInfo; + return this; } public virtual ImmutableList GetProperties() diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs index d6a42e82c7..0e94a3a984 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; +using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending { @@ -14,16 +16,19 @@ namespace Volo.Abp.ObjectExtending ObjectsExtensions = new Dictionary(); } - public virtual ObjectExtensionInfo AddOrUpdate( - Action configureAction = null) + public virtual ObjectExtensionManager AddOrUpdate( + [CanBeNull] Action configureAction = null) + where TObject : IHasExtraProperties { return AddOrUpdate(typeof(TObject), configureAction); } - public virtual ObjectExtensionInfo AddOrUpdate( - Type type, - Action configureAction = null) + public virtual ObjectExtensionManager AddOrUpdate( + [NotNull] Type type, + [CanBeNull] Action configureAction = null) { + Check.NotNull(type, nameof(type)); + var extensionInfo = ObjectsExtensions.GetOrAdd( type, () => new ObjectExtensionInfo(type) @@ -31,7 +36,7 @@ namespace Volo.Abp.ObjectExtending configureAction?.Invoke(extensionInfo); - return extensionInfo; + return this; } public virtual ObjectExtensionInfo GetOrNull() @@ -39,8 +44,10 @@ namespace Volo.Abp.ObjectExtending return GetOrNull(typeof(TObject)); } - public virtual ObjectExtensionInfo GetOrNull(Type type) + public virtual ObjectExtensionInfo GetOrNull([NotNull] Type type) { + Check.NotNull(type, nameof(type)); + return ObjectsExtensions.GetOrDefault(type); } } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManagerExtensions.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManagerExtensions.cs new file mode 100644 index 0000000000..d21a8c22e1 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManagerExtensions.cs @@ -0,0 +1,44 @@ +using System; +using JetBrains.Annotations; +using Volo.Abp.Data; + +namespace Volo.Abp.ObjectExtending +{ + public static class ObjectExtensionManagerExtensions + { + public static ObjectExtensionManager AddOrUpdateProperty( + [NotNull] this ObjectExtensionManager objectExtensionManager, + [NotNull] string propertyName, + [CanBeNull] Action configureAction = null) + where TObject : IHasExtraProperties + { + return objectExtensionManager.AddOrUpdateProperty( + typeof(TObject), + typeof(TProperty), + propertyName, + configureAction + ); + } + + public static ObjectExtensionManager AddOrUpdateProperty( + [NotNull] this ObjectExtensionManager objectExtensionManager, + [NotNull] Type objectType, + [NotNull] Type propertyType, + [NotNull] string propertyName, + [CanBeNull] Action configureAction = null) + { + Check.NotNull(objectExtensionManager, nameof(objectExtensionManager)); + + return objectExtensionManager.AddOrUpdate( + objectType, + options => + { + options.AddOrUpdateProperty( + propertyType, + propertyName, + configureAction + ); + }); + } + } +} \ 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 58879cfd59..ca08f0f03b 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; +using System; +using System.Collections.Generic; using JetBrains.Annotations; namespace Volo.Abp.ObjectExtending @@ -12,15 +12,19 @@ namespace Volo.Abp.ObjectExtending [NotNull] public string Name { get; } + [NotNull] + public Type Type { get; } + //[NotNull] //TODO: Will be implemented, probably in the v2.5 //public List ValidationAttributes { get; } [NotNull] public Dictionary Configuration { get; } - public ObjectExtensionPropertyInfo(ObjectExtensionInfo objectExtension, string name) + public ObjectExtensionPropertyInfo([NotNull] ObjectExtensionInfo objectExtension, [NotNull] Type type, [NotNull] string name) { ObjectExtension = Check.NotNull(objectExtension, nameof(objectExtension)); + Type = Check.NotNull(type, nameof(type)); Name = Check.NotNull(name, nameof(name)); //ValidationAttributes = new List(); From 9f3d7ab0b7af61448e5598abbcf178cd2dca919f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 23:40:06 +0300 Subject: [PATCH 15/24] Added Object Extensions empty document --- ...Customizing-Application-Modules-Extending-Entities.md | 9 +++++---- docs/en/Object-Extensions.md | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 docs/en/Object-Extensions.md diff --git a/docs/en/Customizing-Application-Modules-Extending-Entities.md b/docs/en/Customizing-Application-Modules-Extending-Entities.md index 376e7a1517..be28465ff7 100644 --- a/docs/en/Customizing-Application-Modules-Extending-Entities.md +++ b/docs/en/Customizing-Application-Modules-Extending-Entities.md @@ -40,10 +40,11 @@ To overcome the difficulties described above, ABP Framework entity extension sys Assume that you want to add a `SocialSecurityNumber` to the `IdentityUser` entity of the [Identity Module](Modules/Identity.md). You can use the `ObjectExtensionManager`: ````csharp -ObjectExtensionManager.Instance.MapEfCoreProperty( - "SocialSecurityNumber", - b => { b.HasMaxLength(32); } -); +ObjectExtensionManager.Instance + .MapEfCoreProperty( + "SocialSecurityNumber", + b => { b.HasMaxLength(32); } + ); ```` * You provide the `IdentityUser` as the entity name, `string` as the type of the new property, `SocialSecurityNumber` as the property name (also, the field name in the database table). diff --git a/docs/en/Object-Extensions.md b/docs/en/Object-Extensions.md new file mode 100644 index 0000000000..fad3ff2b0c --- /dev/null +++ b/docs/en/Object-Extensions.md @@ -0,0 +1,3 @@ +# Object Extensions + +TODO \ No newline at end of file From 8f7d115ae2506221e555e08e743d786d6be70d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 23:45:00 +0300 Subject: [PATCH 16/24] Apply object extension changes to the app template. --- ...MyProjectName.Application.Contracts.csproj | 1 + ...MyProjectNameApplicationContractsModule.cs | 9 ++++-- .../MyProjectNameDtoExtensions.cs | 29 +++++++++++++++++++ .../MongoDb/MyProjectNameEntityExtensions.cs | 29 +++++++++++++++++++ .../MongoDb/MyProjectNameMongoDbModule.cs | 5 ++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameDtoExtensions.cs create mode 100644 templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameEntityExtensions.cs diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyCompanyName.MyProjectName.Application.Contracts.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyCompanyName.MyProjectName.Application.Contracts.csproj index 818b7059de..fe2e40eb14 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyCompanyName.MyProjectName.Application.Contracts.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyCompanyName.MyProjectName.Application.Contracts.csproj @@ -12,6 +12,7 @@ + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameApplicationContractsModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameApplicationContractsModule.cs index 7dc5f632b7..5c3ba41364 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameApplicationContractsModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameApplicationContractsModule.cs @@ -2,6 +2,7 @@ using Volo.Abp.FeatureManagement; using Volo.Abp.Identity; using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending; using Volo.Abp.PermissionManagement; using Volo.Abp.TenantManagement; @@ -13,10 +14,14 @@ namespace MyCompanyName.MyProjectName typeof(AbpFeatureManagementApplicationContractsModule), typeof(AbpIdentityApplicationContractsModule), typeof(AbpPermissionManagementApplicationContractsModule), - typeof(AbpTenantManagementApplicationContractsModule) + typeof(AbpTenantManagementApplicationContractsModule), + typeof(AbpObjectExtendingModule) )] public class MyProjectNameApplicationContractsModule : AbpModule { - + public override void PreConfigureServices(ServiceConfigurationContext context) + { + MyProjectNameDtoExtensions.Configure(); + } } } diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameDtoExtensions.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameDtoExtensions.cs new file mode 100644 index 0000000000..35af461b46 --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Application.Contracts/MyProjectNameDtoExtensions.cs @@ -0,0 +1,29 @@ +using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.Threading; + +namespace MyCompanyName.MyProjectName +{ + public static class MyProjectNameDtoExtensions + { + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public static void Configure() + { + OneTimeRunner.Run(() => + { + /* You can add extension properties to DTOs + * defined in the depended modules. + * + * Example: + * + * ObjectExtensionManager.Instance + * .AddOrUpdateProperty("Title"); + * + * See the documentation for more: + * https://docs.abp.io/en/abp/latest/Object-Extensions + */ + }); + } + } +} \ No newline at end of file diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameEntityExtensions.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameEntityExtensions.cs new file mode 100644 index 0000000000..79107d9ce6 --- /dev/null +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameEntityExtensions.cs @@ -0,0 +1,29 @@ +using Volo.Abp.Identity; +using Volo.Abp.ObjectExtending; +using Volo.Abp.Threading; + +namespace MyCompanyName.MyProjectName.MongoDB +{ + public static class MyProjectNameEntityExtensions + { + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public static void Configure() + { + OneTimeRunner.Run(() => + { + /* You can extension properties to entities + * defined in the depended modules. + * + * Example: + * + * ObjectExtensionManager.Instance + * .AddOrUpdateProperty("Title"); + * + * See the documentation for more: + * https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities + */ + }); + } + } +} \ No newline at end of file diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameMongoDbModule.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameMongoDbModule.cs index 5d3bfabab5..c502d0f924 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameMongoDbModule.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.MongoDB/MongoDb/MyProjectNameMongoDbModule.cs @@ -24,6 +24,11 @@ namespace MyCompanyName.MyProjectName.MongoDB )] public class MyProjectNameMongoDbModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + MyProjectNameEntityExtensions.Configure(); + } + public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddMongoDbContext(options => From 049c18ffd4bf0fd2defbd54483df21890d0dafc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sat, 28 Mar 2020 23:51:39 +0300 Subject: [PATCH 17/24] Fix mapping problems. --- .../AbpIdentityWebAutoMapperProfile.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs index f29659efe6..b0154f543f 100644 --- a/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs +++ b/modules/identity/src/Volo.Abp.Identity.Web/AbpIdentityWebAutoMapperProfile.cs @@ -22,6 +22,7 @@ namespace Volo.Abp.Identity.Web //CreateModal CreateMap() + .Ignore(x => x.ExtraProperties) .ForMember(dest => dest.RoleNames, opt => opt.Ignore()); CreateMap() @@ -29,6 +30,7 @@ namespace Volo.Abp.Identity.Web //EditModal CreateMap() + .Ignore(x => x.ExtraProperties) .ForMember(dest => dest.RoleNames, opt => opt.Ignore()); CreateMap() @@ -41,10 +43,12 @@ namespace Volo.Abp.Identity.Web CreateMap(); //CreateModal - CreateMap(); + CreateMap() + .Ignore(x => x.ExtraProperties); //EditModal - CreateMap(); + CreateMap() + .Ignore(x => x.ExtraProperties); } } } From 497fb6280abe00ed90567de58e66912a71c90806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 09:11:52 +0300 Subject: [PATCH 18/24] Fix HasExtraPropertiesObjectExtendingExtensions --- .../HasExtraPropertiesObjectExtendingExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4226bb30f7..92dfeb8d19 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -33,7 +33,7 @@ namespace Volo.Abp.ObjectExtending return; } - var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); + var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); if (definitionCheck.HasFlag(MappingPropertyDefinitionCheck.Destination) && destinationObjectExtension == null) { From 4ad1b13996e2f8c7d1655ccbdbe560513bac410a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 09:13:17 +0300 Subject: [PATCH 19/24] Added Volo.Abp.ObjectExtending.Tests project --- framework/Volo.Abp.sln | 9 ++- .../Volo.Abp.ObjectExtending.Tests.csproj | 16 ++++ .../AbpObjectExtendingTestBase.cs | 9 +++ .../AbpObjectExtendingTestModule.cs | 24 ++++++ ...opertiesObjectExtendingExtensions_Tests.cs | 73 +++++++++++++++++++ .../TestObjects/ExtensibleTestPerson.cs | 7 ++ .../TestObjects/ExtensibleTestPersonDto.cs | 7 ++ 7 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo.Abp.ObjectExtending.Tests.csproj create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestBase.cs create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPerson.cs create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPersonDto.cs diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 16327abcad..3db0998855 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -275,7 +275,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.UI. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Http.Client.IdentityModel.Web.Tests", "test\Volo.Abp.Http.Client.IdentityModel.Web.Tests\Volo.Abp.Http.Client.IdentityModel.Web.Tests.csproj", "{E1963439-2BE5-4DB5-8438-2A9A792A1ADA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.ObjectExtending", "src\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj", "{D1815C77-16D6-4F99-8814-69065CD89FB3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.ObjectExtending", "src\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj", "{D1815C77-16D6-4F99-8814-69065CD89FB3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.ObjectExtending.Tests", "test\Volo.Abp.ObjectExtending.Tests\Volo.Abp.ObjectExtending.Tests.csproj", "{17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -823,6 +825,10 @@ Global {D1815C77-16D6-4F99-8814-69065CD89FB3}.Debug|Any CPU.Build.0 = Debug|Any CPU {D1815C77-16D6-4F99-8814-69065CD89FB3}.Release|Any CPU.ActiveCfg = Release|Any CPU {D1815C77-16D6-4F99-8814-69065CD89FB3}.Release|Any CPU.Build.0 = Release|Any CPU + {17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -963,6 +969,7 @@ Global {0C498CF2-D052-4BF7-AD35-509A90F69707} = {447C8A77-E5F0-4538-8687-7383196D04EA} {E1963439-2BE5-4DB5-8438-2A9A792A1ADA} = {447C8A77-E5F0-4538-8687-7383196D04EA} {D1815C77-16D6-4F99-8814-69065CD89FB3} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {17F8CA89-D9A2-4863-A5BD-B8E4D2901FD5} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo.Abp.ObjectExtending.Tests.csproj b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo.Abp.ObjectExtending.Tests.csproj new file mode 100644 index 0000000000..0a18e0c44b --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo.Abp.ObjectExtending.Tests.csproj @@ -0,0 +1,16 @@ + + + + + + netcoreapp3.1 + + + + + + + + + + diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestBase.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestBase.cs new file mode 100644 index 0000000000..b01ff201c7 --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestBase.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Testing; + +namespace Volo.Abp.ObjectExtending +{ + public abstract class AbpObjectExtendingTestBase : AbpIntegratedTest + { + + } +} 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 new file mode 100644 index 0000000000..30db2aba71 --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/AbpObjectExtendingTestModule.cs @@ -0,0 +1,24 @@ +using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending.TestObjects; +using Volo.Abp.Threading; + +namespace Volo.Abp.ObjectExtending +{ + [DependsOn(typeof(AbpObjectExtendingModule))] + public class AbpObjectExtendingTestModule : AbpModule + { + private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); + + public override void PreConfigureServices(ServiceConfigurationContext context) + { + OneTimeRunner.Run(() => + { + ObjectExtensionManager.Instance + .AddOrUpdateProperty("Name") + .AddOrUpdateProperty("Age") + .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 new file mode 100644 index 0000000000..727ec25646 --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions_Tests.cs @@ -0,0 +1,73 @@ +using Shouldly; +using Volo.Abp.Data; +using Volo.Abp.ObjectExtending.TestObjects; +using Xunit; + +namespace Volo.Abp.ObjectExtending +{ + public class HasExtraPropertiesObjectExtendingExtensions_Tests : AbpObjectExtendingTestBase + { + private readonly ExtensibleTestPerson _person; + + public HasExtraPropertiesObjectExtendingExtensions_Tests() + { + _person = new ExtensibleTestPerson() + .SetProperty("Name", "John") + .SetProperty("Age", 42) + .SetProperty("ChildCount", 2) + .SetProperty("Sex", "male"); + } + + [Fact] + public void MapExtraPropertiesTo_Should_Only_Map_Defined_Properties_By_Default() + { + var personDto = new ExtensibleTestPersonDto(); + + _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 + } + + [Fact] + public void MapExtraPropertiesTo_Should_Only_Map_Source_Defined_Properties_If_Requested() + { + var personDto = new ExtensibleTestPersonDto(); + + _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 + } + + [Fact] + public void MapExtraPropertiesTo_Should_Only_Map_Destination_Defined_Properties_If_Requested() + { + var personDto = new ExtensibleTestPersonDto(); + + _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 + } + + [Fact] + public void MapExtraPropertiesTo_Should_Copy_all_With_No_Property_Definition_Check() + { + var personDto = new ExtensibleTestPersonDto(); + + _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"); + } + } +} diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPerson.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPerson.cs new file mode 100644 index 0000000000..bd24209212 --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPerson.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.ObjectExtending.TestObjects +{ + public class ExtensibleTestPerson : ExtensibleObject + { + + } +} diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPersonDto.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPersonDto.cs new file mode 100644 index 0000000000..62f0f94866 --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/TestObjects/ExtensibleTestPersonDto.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.ObjectExtending.TestObjects +{ + public class ExtensibleTestPersonDto : ExtensibleObject + { + + } +} From bb83eccd6f49a01898e2a9a9f18b7dbbc969915e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 09:52:05 +0300 Subject: [PATCH 20/24] Revised AbpAutoMapperExtensibleDtoExtensions and more added tests. --- .../AbpAutoMapperExtensibleDtoExtensions.cs | 24 +++----- ...xtraPropertiesObjectExtendingExtensions.cs | 51 +++++++++++++---- ...AutoMapperExtensibleDtoExtensions_Tests.cs | 41 ++++++++++++++ .../Volo.Abp.AutoMapper.Tests.csproj | 2 +- .../Abp/AutoMapper/AutoMapperTestModule.cs | 9 ++- .../AutoMapper/SampleClasses/MyMapProfile.cs | 4 ++ .../AbpObjectExtendingTestModule.cs | 5 +- ...opertiesObjectExtendingExtensions_Tests.cs | 56 +++++++++---------- 8 files changed, 133 insertions(+), 59 deletions(-) create mode 100644 framework/test/Volo.Abp.AutoMapper.Tests/AutoMapper/AbpAutoMapperExtensibleDtoExtensions_Tests.cs 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 } } } From 0053c02946c05d783421e53d87604e329686b4ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 12:32:00 +0300 Subject: [PATCH 21/24] Added Check.AssignableTo --- framework/src/Volo.Abp.Core/Volo/Abp/Check.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs index f942f44b0f..d1ce8b6e76 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs @@ -121,6 +121,21 @@ namespace Volo.Abp return value; } + [ContractAnnotation("type:null => halt")] + public static Type AssignableTo( + Type type, + [InvokerParameterName] [NotNull] string parameterName) + { + NotNull(type, parameterName); + + if (!type.IsAssignableTo()) + { + throw new ArgumentException($"{parameterName} should be assignable to the {typeof(TBaseType).GetFullNameWithAssemblyName()}!"); + } + + return type; + } + public static string Length( [CanBeNull] string value, [InvokerParameterName] [NotNull] string parameterName, From edf8f82fc25de49afbcf0ec384ed0f3fea3c5655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 12:40:02 +0300 Subject: [PATCH 22/24] Refactor ObjectExtending. --- .../AbpAutoMapperExtensibleDtoExtensions.cs | 2 +- .../AbpEntityTypeBuilderExtensions.cs | 7 +- ...xtraPropertiesObjectExtendingExtensions.cs | 91 ++++++++++++++----- ....cs => MappingPropertyDefinitionChecks.cs} | 2 +- .../ObjectExtending/ObjectExtensionInfo.cs | 11 ++- .../ObjectExtending/ObjectExtensionManager.cs | 11 ++- .../ObjectExtensionPropertyInfo.cs | 9 +- ...opertiesObjectExtendingExtensions_Tests.cs | 6 +- 8 files changed, 101 insertions(+), 38 deletions(-) rename framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/{MappingPropertyDefinitionCheck.cs => MappingPropertyDefinitionChecks.cs} (92%) diff --git a/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs b/framework/src/Volo.Abp.AutoMapper/AutoMapper/AbpAutoMapperExtensibleDtoExtensions.cs index ab07f6235e..031a3a9948 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, - MappingPropertyDefinitionCheck definitionCheck = MappingPropertyDefinitionCheck.Both) + MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) where TDestination : IHasExtraProperties where TSource : IHasExtraProperties { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs index b64866f8be..0a84b6871d 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs @@ -69,14 +69,17 @@ namespace Volo.Abp.EntityFrameworkCore.Modeling } public static void ConfigureObjectExtensions(this EntityTypeBuilder b) - where T : class + where T : class, IHasExtraProperties { b.As().TryConfigureObjectExtensions(); } public static void TryConfigureObjectExtensions(this EntityTypeBuilder b) { - ObjectExtensionManager.Instance.ConfigureEfCoreEntity(b); + if (b.Metadata.ClrType.IsAssignableTo()) + { + ObjectExtensionManager.Instance.ConfigureEfCoreEntity(b); + } } public static void ConfigureSoftDelete(this EntityTypeBuilder b) 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 61ee13fc89..25156f298c 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/HasExtraPropertiesObjectExtendingExtensions.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using JetBrains.Annotations; using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending @@ -11,26 +13,31 @@ namespace Volo.Abp.ObjectExtending /// to the object. /// /// Checks property definitions (over the ) - /// based on the preference. + /// based on the preference. /// /// Source class type /// Destination class type /// The source object /// The destination object - /// + /// /// Controls which properties to map. /// public static void MapExtraPropertiesTo( - this TSource source, - TDestination destination, - MappingPropertyDefinitionCheck definitionCheck = MappingPropertyDefinitionCheck.Both) + [NotNull] this TSource source, + [NotNull] TDestination destination, + MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { - MapExtraPropertiesTo( + Check.NotNull(source, nameof(source)); + Check.NotNull(destination, nameof(destination)); + + MapExtraPropertiesTo( + typeof(TSource), + typeof(TDestination), source.ExtraProperties, destination.ExtraProperties, - definitionCheck + definitionChecks ); } @@ -39,45 +46,82 @@ namespace Volo.Abp.ObjectExtending /// to the object. /// /// Checks property definitions (over the ) - /// based on the preference. + /// 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) + [NotNull] Dictionary sourceDictionary, + [NotNull] Dictionary destinationDictionary, + MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) where TSource : IHasExtraProperties where TDestination : IHasExtraProperties { - var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); - if (definitionCheck.HasFlag(MappingPropertyDefinitionCheck.Source) && + MapExtraPropertiesTo( + typeof(TSource), + typeof(TDestination), + sourceDictionary, + destinationDictionary, + definitionChecks + ); + } + + /// + /// Copies extra properties from the object + /// to the object. + /// + /// Checks property definitions (over the ) + /// based on the preference. + /// + /// Source 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( + [NotNull] Type sourceType, + [NotNull] Type destinationType, + [NotNull] Dictionary sourceDictionary, + [NotNull] Dictionary destinationDictionary, + MappingPropertyDefinitionChecks definitionChecks = MappingPropertyDefinitionChecks.Both) + { + Check.AssignableTo(sourceType, nameof(sourceType)); + Check.AssignableTo(destinationType, nameof(destinationType)); + Check.NotNull(sourceDictionary, nameof(sourceDictionary)); + Check.NotNull(destinationDictionary, nameof(destinationDictionary)); + + var sourceObjectExtension = ObjectExtensionManager.Instance.GetOrNull(sourceType); + if (definitionChecks.HasFlag(MappingPropertyDefinitionChecks.Source) && sourceObjectExtension == null) { return; } - var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(); - if (definitionCheck.HasFlag(MappingPropertyDefinitionCheck.Destination) && + var destinationObjectExtension = ObjectExtensionManager.Instance.GetOrNull(destinationType); + if (definitionChecks.HasFlag(MappingPropertyDefinitionChecks.Destination) && destinationObjectExtension == null) { return; } - if (definitionCheck == MappingPropertyDefinitionCheck.None) + if (definitionChecks == MappingPropertyDefinitionChecks.None) { foreach (var keyValue in sourceDictionary) { destinationDictionary[keyValue.Key] = keyValue.Value; } } - else if (definitionCheck == MappingPropertyDefinitionCheck.Source) + else if (definitionChecks == MappingPropertyDefinitionChecks.Source) { + Debug.Assert(sourceObjectExtension != null, nameof(sourceObjectExtension) + " != null"); + foreach (var property in sourceObjectExtension.GetProperties()) { if (!sourceDictionary.ContainsKey(property.Name)) @@ -88,8 +132,10 @@ namespace Volo.Abp.ObjectExtending destinationDictionary[property.Name] = sourceDictionary[property.Name]; } } - else if (definitionCheck == MappingPropertyDefinitionCheck.Destination) + else if (definitionChecks == MappingPropertyDefinitionChecks.Destination) { + Debug.Assert(destinationObjectExtension != null, nameof(destinationObjectExtension) + " != null"); + foreach (var keyValue in sourceDictionary) { if (!destinationObjectExtension.HasProperty(keyValue.Key)) @@ -100,8 +146,11 @@ namespace Volo.Abp.ObjectExtending destinationDictionary[keyValue.Key] = keyValue.Value; } } - else if (definitionCheck == MappingPropertyDefinitionCheck.Both) + else if (definitionChecks == MappingPropertyDefinitionChecks.Both) { + Debug.Assert(sourceObjectExtension != null, nameof(sourceObjectExtension) + " != null"); + Debug.Assert(destinationObjectExtension != null, nameof(destinationObjectExtension) + " != null"); + foreach (var property in sourceObjectExtension.GetProperties()) { if (!sourceDictionary.ContainsKey(property.Name)) @@ -119,7 +168,7 @@ namespace Volo.Abp.ObjectExtending } else { - throw new NotImplementedException(definitionCheck + " was not implemented!"); + throw new NotImplementedException(definitionChecks + " was not implemented!"); } } } diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionChecks.cs similarity index 92% rename from framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs rename to framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionChecks.cs index f1bd9c3c66..b33638fa7c 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionCheck.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionChecks.cs @@ -3,7 +3,7 @@ namespace Volo.Abp.ObjectExtending { [Flags] - public enum MappingPropertyDefinitionCheck : byte + public enum MappingPropertyDefinitionChecks : byte { /// /// No check. Copy all extra properties from the source to the destination. diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index 6f59465660..14d527991f 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -2,20 +2,24 @@ using System.Collections.Generic; using System.Collections.Immutable; using JetBrains.Annotations; +using Volo.Abp.Data; namespace Volo.Abp.ObjectExtending { public class ObjectExtensionInfo { + [NotNull] public Type Type { get; } + [NotNull] protected Dictionary Properties { get; } + [NotNull] public Dictionary Configuration { get; } - public ObjectExtensionInfo(Type type) + public ObjectExtensionInfo([NotNull] Type type) { - Type = type; + Type = Check.AssignableTo(type, nameof(type)); Properties = new Dictionary(); Configuration = new Dictionary(); } @@ -25,6 +29,7 @@ namespace Volo.Abp.ObjectExtending return Properties.ContainsKey(propertyName); } + [NotNull] public virtual ObjectExtensionInfo AddOrUpdateProperty( [NotNull] string propertyName, [CanBeNull] Action configureAction = null) @@ -36,6 +41,7 @@ namespace Volo.Abp.ObjectExtending ); } + [NotNull] public virtual ObjectExtensionInfo AddOrUpdateProperty( [NotNull] Type propertyType, [NotNull] string propertyName, @@ -54,6 +60,7 @@ namespace Volo.Abp.ObjectExtending return this; } + [NotNull] public virtual ImmutableList GetProperties() { return Properties.Values.ToImmutableList(); diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs index 0e94a3a984..cbc2aa3baa 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -16,6 +16,7 @@ namespace Volo.Abp.ObjectExtending ObjectsExtensions = new Dictionary(); } + [NotNull] public virtual ObjectExtensionManager AddOrUpdate( [CanBeNull] Action configureAction = null) where TObject : IHasExtraProperties @@ -23,12 +24,13 @@ namespace Volo.Abp.ObjectExtending return AddOrUpdate(typeof(TObject), configureAction); } + [NotNull] public virtual ObjectExtensionManager AddOrUpdate( [NotNull] Type type, [CanBeNull] Action configureAction = null) { - Check.NotNull(type, nameof(type)); - + Check.AssignableTo(type, nameof(type)); + var extensionInfo = ObjectsExtensions.GetOrAdd( type, () => new ObjectExtensionInfo(type) @@ -39,14 +41,17 @@ namespace Volo.Abp.ObjectExtending return this; } + [CanBeNull] public virtual ObjectExtensionInfo GetOrNull() + where TObject : IHasExtraProperties { return GetOrNull(typeof(TObject)); } + [CanBeNull] public virtual ObjectExtensionInfo GetOrNull([NotNull] Type type) { - Check.NotNull(type, nameof(type)); + Check.AssignableTo(type, nameof(type)); return ObjectsExtensions.GetOrDefault(type); } 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 ca08f0f03b..af5d0c2ce4 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -15,19 +15,18 @@ namespace Volo.Abp.ObjectExtending [NotNull] public Type Type { get; } - //[NotNull] //TODO: Will be implemented, probably in the v2.5 - //public List ValidationAttributes { get; } - [NotNull] public Dictionary Configuration { get; } - public ObjectExtensionPropertyInfo([NotNull] ObjectExtensionInfo objectExtension, [NotNull] Type type, [NotNull] string name) + public ObjectExtensionPropertyInfo( + [NotNull] ObjectExtensionInfo objectExtension, + [NotNull] Type type, + [NotNull] string name) { ObjectExtension = Check.NotNull(objectExtension, nameof(objectExtension)); Type = Check.NotNull(type, nameof(type)); Name = Check.NotNull(name, nameof(name)); - //ValidationAttributes = new List(); Configuration = new Dictionary(); } } 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 36d1f1988b..a51d9514b2 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 @@ -37,7 +37,7 @@ namespace Volo.Abp.ObjectExtending [Fact] public void MapExtraPropertiesTo_Should_Only_Map_Source_Defined_Properties_If_Requested() { - _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionCheck.Source); + _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionChecks.Source); _personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes _personDto.GetProperty("Age").ShouldBe(42); //Defined in source @@ -49,7 +49,7 @@ namespace Volo.Abp.ObjectExtending [Fact] public void MapExtraPropertiesTo_Should_Only_Map_Destination_Defined_Properties_If_Requested() { - _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionCheck.Destination); + _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionChecks.Destination); _personDto.GetProperty("Name").ShouldBe("John"); //Defined in both classes _personDto.GetProperty("ChildCount").ShouldBe(2); //Defined in destination @@ -61,7 +61,7 @@ namespace Volo.Abp.ObjectExtending [Fact] public void MapExtraPropertiesTo_Should_Copy_all_With_No_Property_Definition_Check() { - _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionCheck.None); + _person.MapExtraPropertiesTo(_personDto, MappingPropertyDefinitionChecks.None); _personDto.GetProperty("Name").ShouldBe("John"); _personDto.GetProperty("Age").ShouldBe(42); From 01d2ea0b00b7fc58d165e7d0ee70133b2c758e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 12:49:16 +0300 Subject: [PATCH 23/24] Refactor EF Core entity extensions. --- framework/src/Volo.Abp.Core/Volo/Abp/Check.cs | 2 +- .../EfCoreObjectExtensionManagerExtensions.cs | 71 ++++++++++--------- ...reObjectExtensionPropertyInfoExtensions.cs | 18 +++-- ...tensionPropertyInfoEfCoreMappingOptions.cs | 1 + 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs b/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs index d1ce8b6e76..7001925745 100644 --- a/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs +++ b/framework/src/Volo.Abp.Core/Volo/Abp/Check.cs @@ -130,7 +130,7 @@ namespace Volo.Abp if (!type.IsAssignableTo()) { - throw new ArgumentException($"{parameterName} should be assignable to the {typeof(TBaseType).GetFullNameWithAssemblyName()}!"); + throw new ArgumentException($"{parameterName} (type of {type.AssemblyQualifiedName}) should be assignable to the {typeof(TBaseType).GetFullNameWithAssemblyName()}!"); } return type; diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs index a7c392f7c4..52dca0c105 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionManagerExtensions.cs @@ -1,19 +1,21 @@ using System; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; namespace Volo.Abp.ObjectExtending { public static class EfCoreObjectExtensionManagerExtensions { - public static ObjectExtensionManager MapEfCoreProperty( - this ObjectExtensionManager objectExtensionManager, - string propertyName, - Action propertyBuildAction) - where TObject : IHasExtraProperties + public static ObjectExtensionManager MapEfCoreProperty( + [NotNull] this ObjectExtensionManager objectExtensionManager, + [NotNull] string propertyName, + [CanBeNull] Action propertyBuildAction = null) + where TEntity : IHasExtraProperties, IEntity { return objectExtensionManager.MapEfCoreProperty( - typeof(TObject), + typeof(TEntity), typeof(TProperty), propertyName, propertyBuildAction @@ -21,14 +23,16 @@ namespace Volo.Abp.ObjectExtending } public static ObjectExtensionManager MapEfCoreProperty( - this ObjectExtensionManager objectExtensionManager, - Type objectType, - Type propertyType, - string propertyName, - Action propertyBuildAction) + [NotNull] this ObjectExtensionManager objectExtensionManager, + [NotNull] Type entityType, + [NotNull] Type propertyType, + [NotNull] string propertyName, + [CanBeNull] Action propertyBuildAction = null) { + Check.NotNull(objectExtensionManager, nameof(objectExtensionManager)); + return objectExtensionManager.AddOrUpdateProperty( - objectType, + entityType, propertyType, propertyName, options => @@ -40,34 +44,37 @@ namespace Volo.Abp.ObjectExtending ); } - public static void ConfigureEfCoreEntity( - this ObjectExtensionManager objectExtensionManager, - EntityTypeBuilder b) - { - var objectExtension = objectExtensionManager.GetOrNull(b.Metadata.ClrType); - if (objectExtension == null) + public static void ConfigureEfCoreEntity( + [NotNull] this ObjectExtensionManager objectExtensionManager, + [NotNull] EntityTypeBuilder typeBuilder) { - return; - } + Check.NotNull(objectExtensionManager, nameof(objectExtensionManager)); + Check.NotNull(typeBuilder, nameof(typeBuilder)); - foreach (var property in objectExtension.GetProperties()) - { - var efCoreMapping = property.GetEfCoreMappingOrNull(); - if (efCoreMapping == null) + var objectExtension = objectExtensionManager.GetOrNull(typeBuilder.Metadata.ClrType); + if (objectExtension == null) { - continue; + return; } - /* Prevent multiple calls to the entityTypeBuilder.Property(...) method */ - if (b.Metadata.FindProperty(property.Name) != null) + foreach (var property in objectExtension.GetProperties()) { - continue; - } + var efCoreMapping = property.GetEfCoreMappingOrNull(); + if (efCoreMapping == null) + { + continue; + } + + /* Prevent multiple calls to the entityTypeBuilder.Property(...) method */ + if (typeBuilder.Metadata.FindProperty(property.Name) != null) + { + continue; + } - var propertyBuilder = b.Property(property.Type, property.Name); + var propertyBuilder = typeBuilder.Property(property.Type, property.Name); - efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder); + efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder); + } } } } -} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs index e76edb167a..fda5d88ceb 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/EfCoreObjectExtensionPropertyInfoExtensions.cs @@ -9,6 +9,7 @@ namespace Volo.Abp.ObjectExtending { public const string EfCorePropertyConfigurationName = "EfCoreMapping"; + [NotNull] public static ObjectExtensionPropertyInfo MapEfCore( [NotNull] this ObjectExtensionPropertyInfo propertyExtension, [CanBeNull] Action propertyBuildAction = null) @@ -26,15 +27,24 @@ namespace Volo.Abp.ObjectExtending [CanBeNull] public static ObjectExtensionPropertyInfoEfCoreMappingOptions GetEfCoreMappingOrNull( - this ObjectExtensionPropertyInfo propertyExtension) + [NotNull] this ObjectExtensionPropertyInfo propertyExtension) { - return propertyExtension.Configuration.GetOrDefault(EfCorePropertyConfigurationName) + Check.NotNull(propertyExtension, nameof(propertyExtension)); + + return propertyExtension + .Configuration + .GetOrDefault(EfCorePropertyConfigurationName) as ObjectExtensionPropertyInfoEfCoreMappingOptions; } - public static bool IsMappedToFieldForEfCore(this ObjectExtensionPropertyInfo propertyExtension) + public static bool IsMappedToFieldForEfCore( + [NotNull] this ObjectExtensionPropertyInfo propertyExtension) { - return propertyExtension.Configuration.ContainsKey(EfCorePropertyConfigurationName); + Check.NotNull(propertyExtension, nameof(propertyExtension)); + + return propertyExtension + .Configuration + .ContainsKey(EfCorePropertyConfigurationName); } } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs index 0c9909f5d7..4189c87962 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfoEfCoreMappingOptions.cs @@ -20,6 +20,7 @@ namespace Volo.Abp.ObjectExtending [CanBeNull] Action propertyBuildAction = null) { ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty)); + PropertyBuildAction = propertyBuildAction; } } From 3ba4accc596979dd803ec4a2c85be46c4dc7bc84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Sun, 29 Mar 2020 13:12:14 +0300 Subject: [PATCH 24/24] Added ObjectExtensionManager_Tests --- .../Properties/AssemblyInfo.cs | 3 + .../ObjectExtending/ObjectExtensionInfo.cs | 9 +++ .../ObjectExtending/ObjectExtensionManager.cs | 9 ++- .../ObjectExtensionManager_Tests.cs | 63 +++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.ObjectExtending/Properties/AssemblyInfo.cs create mode 100644 framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs diff --git a/framework/src/Volo.Abp.ObjectExtending/Properties/AssemblyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..fe0b656805 --- /dev/null +++ b/framework/src/Volo.Abp.ObjectExtending/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Volo.Abp.ObjectExtending.Tests")] diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs index 14d527991f..89ecbab574 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs @@ -65,5 +65,14 @@ namespace Volo.Abp.ObjectExtending { return Properties.Values.ToImmutableList(); } + + [CanBeNull] + public virtual ObjectExtensionPropertyInfo GetPropertyOrNull( + [NotNull] string propertyName) + { + Check.NotNullOrEmpty(propertyName, nameof(propertyName)); + + return Properties.GetOrDefault(propertyName); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs index cbc2aa3baa..9fd50da492 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using JetBrains.Annotations; using Volo.Abp.Data; @@ -11,7 +12,7 @@ namespace Volo.Abp.ObjectExtending protected Dictionary ObjectsExtensions { get; } - protected ObjectExtensionManager() + protected internal ObjectExtensionManager() { ObjectsExtensions = new Dictionary(); } @@ -55,5 +56,11 @@ namespace Volo.Abp.ObjectExtending return ObjectsExtensions.GetOrDefault(type); } + + [NotNull] + public virtual ImmutableList GetExtendedObjects() + { + return ObjectsExtensions.Values.ToImmutableList(); + } } } \ No newline at end of file diff --git a/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs new file mode 100644 index 0000000000..857e2fd155 --- /dev/null +++ b/framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ObjectExtensionManager_Tests.cs @@ -0,0 +1,63 @@ +using System.Linq; +using Shouldly; +using Xunit; + +namespace Volo.Abp.ObjectExtending +{ + public class ObjectExtensionManager_Tests + { + private readonly ObjectExtensionManager _objectExtensionManager; + + public ObjectExtensionManager_Tests() + { + _objectExtensionManager = new ObjectExtensionManager(); + } + + [Fact] + public void Should_Not_Add_Same_Property_Multiple_Times() + { + _objectExtensionManager + .AddOrUpdateProperty("TestProp") + .AddOrUpdateProperty("TestProp"); + + var objectExtension = _objectExtensionManager.GetOrNull(); + objectExtension.ShouldNotBeNull(); + + var properties = objectExtension.GetProperties(); + properties.Count.ShouldBe(1); + properties.FirstOrDefault(p => p.Name == "TestProp").ShouldNotBeNull(); + } + + [Fact] + public void Should_Update_Property_Configuration() + { + _objectExtensionManager + .AddOrUpdateProperty( + "TestProp", + options => + { + options.Configuration["TestConfig1"] = "TestConfig1-Value"; + } + ).AddOrUpdateProperty( + "TestProp", + options => + { + options.Configuration["TestConfig2"] = "TestConfig2-Value"; + } + ); + + var objectExtension = _objectExtensionManager.GetOrNull(); + objectExtension.ShouldNotBeNull(); + + var property = objectExtension.GetPropertyOrNull("TestProp"); + property.ShouldNotBeNull(); + property.Configuration["TestConfig1"].ShouldBe("TestConfig1-Value"); + property.Configuration["TestConfig2"].ShouldBe("TestConfig2-Value"); + } + + private class MyExtensibleObject : ExtensibleObject + { + + } + } +}