Browse Source

Merge pull request #23277 from abpframework/Mapperly

feat: Add `Volo.Abp.Mapperly` module
pull/23431/head
Halil İbrahim Kalkan 10 months ago
committed by GitHub
parent
commit
ef28115878
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      Directory.Packages.props
  2. 14
      framework/Volo.Abp.sln
  3. 22
      framework/src/Volo.Abp.Mapperly/Microsoft/Extensions/DependencyInjection/AbpAutoMapperServiceCollectionExtensions.cs
  4. 29
      framework/src/Volo.Abp.Mapperly/Volo.Abp.Mapperly.csproj
  5. 27
      framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/AbpMapperlyConventionalRegistrar.cs
  6. 25
      framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/AbpMapperlyModule.cs
  7. 23
      framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/IAbpMapperlyMapper.cs
  8. 14
      framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapExtraPropertiesAttribute.cs
  9. 32
      framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperBase.cs
  10. 145
      framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs
  11. 2
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs
  12. 11
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionChecks.cs
  13. 82
      framework/test/Volo.Abp.Mapperly.Tests/Mapperly/AbpAutoMapperExtensibleDtoExtensions_Tests.cs
  14. 17
      framework/test/Volo.Abp.Mapperly.Tests/Volo.Abp.Mapperly.Tests.csproj
  15. 59
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperlyBeforeAndAfterMethod_Tests.cs
  16. 60
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperlyModule_Basic_Tests.cs
  17. 191
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperlyModule_Specific_ObjectMapper_Tests.cs
  18. 68
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperly_Dependency_Injection_Tests.cs
  19. 86
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpReverseMapperly_Tests.cs
  20. 13
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/MapperlyTestModule.cs
  21. 44
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MapperlyMappers.cs
  22. 10
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntity.cs
  23. 10
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityDto.cs
  24. 10
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityDto2.cs
  25. 43
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityDtoWithMappingMethods.cs
  26. 39
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityToMyEntityDto2Mapper.cs
  27. 8
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEnum.cs
  28. 9
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEnumDto.cs
  29. 10
      framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyNotMappedDto.cs
  30. 1
      nupkg/common.ps1

1
Directory.Packages.props

@ -145,6 +145,7 @@
<PackageVersion Include="RabbitMQ.Client" Version="7.1.2" />
<PackageVersion Include="Rebus" Version="8.8.0" />
<PackageVersion Include="Rebus.ServiceProvider" Version="10.3.0" />
<PackageVersion Include="Riok.Mapperly" Version="4.2.1" />
<PackageVersion Include="Scriban" Version="6.2.1" />
<PackageVersion Include="Serilog" Version="4.2.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />

14
framework/Volo.Abp.sln

@ -491,6 +491,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Bunny.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Timing.Tests", "test\Volo.Abp.Timing.Tests\Volo.Abp.Timing.Tests.csproj", "{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Mapperly", "src\Volo.Abp.Mapperly\Volo.Abp.Mapperly.csproj", "{AF556046-54CD-48BC-9740-3E926DB8B510}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Mapperly.Tests", "test\Volo.Abp.Mapperly.Tests\Volo.Abp.Mapperly.Tests.csproj", "{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.EntityFrameworkCore.MySQL.Pomelo", "src\Volo.Abp.EntityFrameworkCore.MySQL.Pomelo\Volo.Abp.EntityFrameworkCore.MySQL.Pomelo.csproj", "{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}"
EndProject
Global
@ -1467,6 +1471,14 @@ Global
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.Build.0 = Release|Any CPU
{AF556046-54CD-48BC-9740-3E926DB8B510}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF556046-54CD-48BC-9740-3E926DB8B510}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF556046-54CD-48BC-9740-3E926DB8B510}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF556046-54CD-48BC-9740-3E926DB8B510}.Release|Any CPU.Build.0 = Release|Any CPU
{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7}.Release|Any CPU.Build.0 = Release|Any CPU
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -1718,6 +1730,8 @@ Global
{1BBCBA72-CDB6-4882-96EE-D4CD149433A2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{AF556046-54CD-48BC-9740-3E926DB8B510} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{C38926D5-C1E7-47D6-BD0B-D36BE4C19AE7} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{5B49FE47-A4C5-45BE-A903-8215CF5E2FAF} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution

22
framework/src/Volo.Abp.Mapperly/Microsoft/Extensions/DependencyInjection/AbpAutoMapperServiceCollectionExtensions.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Mapperly;
using Volo.Abp.ObjectMapping;
namespace Microsoft.Extensions.DependencyInjection;
public static class AbpAutoMapperServiceCollectionExtensions
{
public static IServiceCollection AddMapperlyObjectMapper(this IServiceCollection services)
{
return services.Replace(
ServiceDescriptor.Transient<IAutoObjectMappingProvider, MapperlyAutoObjectMappingProvider>()
);
}
public static IServiceCollection AddMapperlyObjectMapper<TContext>(this IServiceCollection services)
{
return services.Replace(
ServiceDescriptor.Transient<IAutoObjectMappingProvider<TContext>, MapperlyAutoObjectMappingProvider<TContext>>()
);
}
}

29
framework/src/Volo.Abp.Mapperly/Volo.Abp.Mapperly.csproj

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<WarningsAsErrors>Nullable</WarningsAsErrors>
<AssemblyName>Volo.Abp.Mapperly</AssemblyName>
<PackageId>Volo.Abp.Mapperly</PackageId>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Volo.Abp.Auditing\Volo.Abp.Auditing.csproj" />
<ProjectReference Include="..\Volo.Abp.ObjectExtending\Volo.Abp.ObjectExtending.csproj" />
<ProjectReference Include="..\Volo.Abp.ObjectMapping\Volo.Abp.ObjectMapping.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Riok.Mapperly" />
</ItemGroup>
</Project>

27
framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/AbpMapperlyConventionalRegistrar.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Mapperly;
public class AbpMapperlyConventionalRegistrar : DefaultConventionalRegistrar
{
protected override bool IsConventionalRegistrationDisabled(Type type)
{
return !type.GetInterfaces().Any(x => x.IsGenericType && typeof(IAbpMapperlyMapper<,>) == x.GetGenericTypeDefinition()) ||
base.IsConventionalRegistrationDisabled(type);
}
protected override List<Type> GetExposedServiceTypes(Type type)
{
var exposedServiceTypes = base.GetExposedServiceTypes(type);
var mapperlyInterfaces = type.GetInterfaces().Where(x =>
x.IsGenericType && (typeof(IAbpMapperlyMapper<,>) == x.GetGenericTypeDefinition() ||
typeof(IAbpReverseMapperlyMapper<,>) == x.GetGenericTypeDefinition()));
return exposedServiceTypes
.Union(mapperlyInterfaces)
.Distinct()
.ToList();
}
}

25
framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/AbpMapperlyModule.cs

@ -0,0 +1,25 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Auditing;
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.Mapperly;
[DependsOn(
typeof(AbpObjectMappingModule),
typeof(AbpObjectExtendingModule),
typeof(AbpAuditingModule)
)]
public class AbpMapperlyModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddConventionalRegistrar(new AbpMapperlyConventionalRegistrar());
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddMapperlyObjectMapper();
}
}

23
framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/IAbpMapperlyMapper.cs

@ -0,0 +1,23 @@
namespace Volo.Abp.Mapperly;
public interface IAbpMapperlyMapper<in TSource, TDestination>
{
TDestination Map(TSource source);
void Map(TSource source, TDestination destination);
void BeforeMap(TSource source);
void AfterMap(TSource source, TDestination destination);
}
public interface IAbpReverseMapperlyMapper<TSource, TDestination> : IAbpMapperlyMapper<TSource, TDestination>
{
TSource ReverseMap(TDestination destination);
void ReverseMap(TDestination destination, TSource source);
void BeforeReverseMap(TDestination destination);
void AfterReverseMap(TDestination destination, TSource source);
}

14
framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapExtraPropertiesAttribute.cs

@ -0,0 +1,14 @@
using System;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.Mapperly;
[AttributeUsage(AttributeTargets.Class)]
public class MapExtraPropertiesAttribute : Attribute
{
public MappingPropertyDefinitionChecks DefinitionChecks { get; set; } = MappingPropertyDefinitionChecks.Null;
public string[]? IgnoredProperties { get; set; }
public bool MapToRegularProperties { get; set; }
}

32
framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperBase.cs

@ -0,0 +1,32 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Mapperly;
public abstract class MapperBase<TSource, TDestination> : IAbpMapperlyMapper<TSource, TDestination>, ITransientDependency
{
public abstract TDestination Map(TSource source);
public abstract void Map(TSource source, TDestination destination);
public virtual void BeforeMap(TSource source)
{
}
public virtual void AfterMap(TSource source, TDestination destination)
{
}
}
public abstract class TwoWayMapperBase<TSource, TDestination> : MapperBase<TSource, TDestination>, IAbpReverseMapperlyMapper<TSource, TDestination>
{
public abstract TSource ReverseMap(TDestination destination);
public abstract void ReverseMap(TDestination destination, TSource source);
public virtual void BeforeReverseMap(TDestination destination)
{
}
public virtual void AfterReverseMap(TDestination destination, TSource source)
{
}
}

145
framework/src/Volo.Abp.Mapperly/Volo/Abp/Mapperly/MapperlyAutoObjectMappingProvider.cs

@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Data;
using Volo.Abp.ObjectExtending;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Reflection;
namespace Volo.Abp.Mapperly;
public class MapperlyAutoObjectMappingProvider<TContext> : MapperlyAutoObjectMappingProvider, IAutoObjectMappingProvider<TContext>
{
public MapperlyAutoObjectMappingProvider(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
}
public class MapperlyAutoObjectMappingProvider : IAutoObjectMappingProvider
{
protected IServiceProvider ServiceProvider { get; }
public MapperlyAutoObjectMappingProvider(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
public virtual TDestination Map<TSource, TDestination>(object source)
{
var mapper = ServiceProvider.GetService<IAbpMapperlyMapper<TSource, TDestination>>();
if (mapper != null)
{
mapper.BeforeMap((TSource)source);
var destination = mapper.Map((TSource)source);
TryMapExtraProperties(mapper.GetType().GetSingleAttributeOrNull<MapExtraPropertiesAttribute>(), (TSource)source, destination, new ExtraPropertyDictionary());
mapper.AfterMap((TSource)source, destination);
return destination;
}
var reverseMapper = ServiceProvider.GetService<IAbpReverseMapperlyMapper<TDestination, TSource>>();
if (reverseMapper != null)
{
reverseMapper.BeforeReverseMap((TSource)source);
var destination = reverseMapper.ReverseMap((TSource)source);
TryMapExtraProperties(reverseMapper.GetType().GetSingleAttributeOrNull<MapExtraPropertiesAttribute>(), (TSource)source, destination, GetExtraProperties(destination));
reverseMapper.AfterReverseMap((TSource)source, destination);
return destination;
}
throw new AbpException($"No {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpMapperlyMapper<TSource, TDestination>))} or" +
$" {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpReverseMapperlyMapper<TSource, TDestination>))} was found");
}
public virtual TDestination Map<TSource, TDestination>(TSource source, TDestination destination)
{
var mapper = ServiceProvider.GetService<IAbpMapperlyMapper<TSource, TDestination>>();
if (mapper != null)
{
mapper.BeforeMap(source);
var destinationExtraProperties = GetExtraProperties(destination);
mapper.Map(source, destination);
TryMapExtraProperties(mapper.GetType().GetSingleAttributeOrNull<MapExtraPropertiesAttribute>(), source, destination, destinationExtraProperties);
mapper.AfterMap(source, destination);
return destination;
}
var reverseMapper = ServiceProvider.GetService<IAbpReverseMapperlyMapper<TDestination, TSource>>();
if (reverseMapper != null)
{
reverseMapper.BeforeReverseMap(source);
var destinationExtraProperties = GetExtraProperties(destination);
reverseMapper.ReverseMap(source, destination);
TryMapExtraProperties(reverseMapper.GetType().GetSingleAttributeOrNull<MapExtraPropertiesAttribute>(), source, destination, destinationExtraProperties);
reverseMapper.AfterReverseMap(source, destination);
return destination;
}
throw new AbpException($"No {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpMapperlyMapper<TSource, TDestination>))} or" +
$" {TypeHelper.GetFullNameHandlingNullableAndGenerics(typeof(IAbpReverseMapperlyMapper<TSource, TDestination>))} was found");
}
protected virtual ExtraPropertyDictionary GetExtraProperties<TDestination>(TDestination destination)
{
var extraProperties = new ExtraPropertyDictionary();
if (destination is not IHasExtraProperties hasExtraProperties)
{
return extraProperties;
}
foreach (var property in hasExtraProperties.ExtraProperties)
{
extraProperties.Add(property.Key, property.Value);
}
return extraProperties;
}
protected virtual void TryMapExtraProperties<TSource, TDestination>(MapExtraPropertiesAttribute? mapExtraPropertiesAttribute, TSource source, TDestination destination, ExtraPropertyDictionary destinationExtraProperty)
{
if (mapExtraPropertiesAttribute != null &&
typeof(IHasExtraProperties).IsAssignableFrom(typeof(TDestination)) &&
typeof(IHasExtraProperties).IsAssignableFrom(typeof(TSource)))
{
MapExtraProperties<TSource, TDestination>(
source!.As<IHasExtraProperties>(),
destination!.As<IHasExtraProperties>(),
destinationExtraProperty,
mapExtraPropertiesAttribute.DefinitionChecks,
mapExtraPropertiesAttribute.IgnoredProperties,
mapExtraPropertiesAttribute.MapToRegularProperties
);
}
}
protected virtual void MapExtraProperties<TSource, TDestination>(
IHasExtraProperties source,
IHasExtraProperties destination,
ExtraPropertyDictionary destinationExtraProperty,
MappingPropertyDefinitionChecks? definitionChecks = null,
string[]? ignoredProperties = null,
bool mapToRegularProperties = false)
{
var result = destinationExtraProperty.IsNullOrEmpty()
? new Dictionary<string, object?>()
: new Dictionary<string, object?>(destinationExtraProperty);
if (source.ExtraProperties != null && destination.ExtraProperties != null)
{
ExtensibleObjectMapper
.MapExtraPropertiesTo(
typeof(TSource),
typeof(TDestination),
source.ExtraProperties,
result,
definitionChecks,
ignoredProperties
);
}
ObjectHelper.TrySetProperty(destination, x => x.ExtraProperties, () => new ExtraPropertyDictionary(result));
if (mapToRegularProperties)
{
destination.SetExtraPropertiesToRegularProperties();
}
}
}

2
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectMapper.cs

@ -188,7 +188,7 @@ public static class ExtensibleObjectMapper
return false;
}
if (definitionChecks != null)
if (definitionChecks != null && definitionChecks.Value != MappingPropertyDefinitionChecks.Null)
{
if (definitionChecks.Value.HasFlag(MappingPropertyDefinitionChecks.Source))
{

11
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/MappingPropertyDefinitionChecks.cs

@ -5,20 +5,25 @@ namespace Volo.Abp.ObjectExtending;
[Flags]
public enum MappingPropertyDefinitionChecks : byte
{
/// <summary>
/// Same as Null, We need to use this in Attribute to avoid null checks.
/// </summary>
Null = 0,
/// <summary>
/// No check. Copy all extra properties from the source to the destination.
/// </summary>
None = 0,
None = 1 << 0,
/// <summary>
/// Copy the extra properties defined for the source class.
/// </summary>
Source = 1,
Source = 1 << 1,
/// <summary>
/// Copy the extra properties defined for the destination class.
/// </summary>
Destination = 2,
Destination = 1 << 2,
/// <summary>
/// Copy extra properties defined for both of the source and destination classes.

82
framework/test/Volo.Abp.Mapperly.Tests/Mapperly/AbpAutoMapperExtensibleDtoExtensions_Tests.cs

@ -0,0 +1,82 @@
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Data;
using Volo.Abp.Mapperly;
using Volo.Abp.ObjectExtending.TestObjects;
using Volo.Abp.Testing;
using Xunit;
namespace Mapperly;
public class AbpAutoMapperExtensibleDtoExtensions_Tests : AbpIntegratedTest<MapperlyTestModule>
{
private readonly Volo.Abp.ObjectMapping.IObjectMapper _objectMapper;
public AbpAutoMapperExtensibleDtoExtensions_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<Volo.Abp.ObjectMapping.IObjectMapper>();
}
[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")
.SetProperty("CityName", "Adana");
var personDto = new ExtensibleTestPersonDto()
.SetProperty("ExistingDtoProperty", "existing-value");
_objectMapper.Map(person, personDto);
personDto.GetProperty<string>("Name").ShouldBe("John"); //Defined in both classes
personDto.GetProperty<string>("ExistingDtoProperty").ShouldBe("existing-value"); //Should not clear existing values
personDto.GetProperty<int>("ChildCount").ShouldBe(0); //Not defined in the source, but was set to the default value by ExtensibleTestPersonDto constructor
personDto.GetProperty("CityName").ShouldBeNull(); //Ignored, but was set to the default value by ExtensibleTestPersonDto constructor
personDto.HasProperty("Age").ShouldBeFalse(); //Not defined on the destination
personDto.HasProperty("Sex").ShouldBeFalse(); //Not defined in both classes
}
[Fact]
public void MapExtraProperties_Also_Should_Map_To_RegularProperties()
{
var person = new ExtensibleTestPerson()
.SetProperty("Name", "John")
.SetProperty("Age", 42);
var personDto = new ExtensibleTestPersonWithRegularPropertiesDto()
.SetProperty("IsActive", true);
_objectMapper.Map(person, personDto);
//Defined in both classes
personDto.HasProperty("Name").ShouldBe(false);
personDto.Name.ShouldBe("John");
//Defined in both classes
personDto.HasProperty("Age").ShouldBe(false);
personDto.Age.ShouldBe(42);
//Should not clear existing values
personDto.HasProperty("IsActive").ShouldBe(false);
personDto.IsActive.ShouldBe(true);
}
[Fact(Skip = "Mapperly requires IHasExtraProperties.ExtraPropertyDictionary to be marked as nullable")]
public void MapExtraPropertiesTo_Should_Ignored_If_ExtraProperties_Is_Null()
{
var person = new ExtensibleTestPerson();
person.SetExtraPropertiesAsNull();
var personDto = new ExtensibleTestPersonDto();
personDto.SetExtraPropertiesAsNull();
Should.NotThrow(() => _objectMapper.Map(person, personDto));
person.ExtraProperties.ShouldBe(null);
personDto.ExtraProperties.ShouldBeEmpty();
}
}

17
framework/test/Volo.Abp.Mapperly.Tests/Volo.Abp.Mapperly.Tests.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<AssemblyName>Volo.Abp.Mapperly.Tests</AssemblyName>
<PackageId>Volo.Abp.Mapperly.Tests</PackageId>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Mapperly\Volo.Abp.Mapperly.csproj" />
<ProjectReference Include="..\..\test\Volo.Abp.ObjectExtending.Tests\Volo.Abp.ObjectExtending.Tests.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>
</Project>

59
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperlyBeforeAndAfterMethod_Tests.cs

@ -0,0 +1,59 @@
using Microsoft.Extensions.DependencyInjection;
using Riok.Mapperly.Abstractions;
using Shouldly;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Mapperly;
public class MyClass
{
public string Id { get; set; }
public string Name { get; set; }
}
public class MyClassDto
{
public string Id { get; set; }
public string Name { get; set; }
}
[Mapper]
public partial class MyClassMapper : MapperBase<MyClass, MyClassDto>
{
public override partial MyClassDto Map(MyClass source);
public override partial void Map(MyClass source, MyClassDto destination);
public override void BeforeMap(MyClass source)
{
source.Name = "BeforeMap " + source.Name;
}
public override void AfterMap(MyClass source, MyClassDto destination)
{
destination.Name = source.Name + " AfterMap";
}
}
public class AbpMapperlyBeforeAndAfterMethod_Tests : AbpIntegratedTest<MapperlyTestModule>
{
private readonly IObjectMapper _objectMapper;
public AbpMapperlyBeforeAndAfterMethod_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
}
[Fact]
public void BeforeAndAfterMethods_Should_Be_Called_When_Mapping()
{
var myClass = new MyClass { Id = "1", Name = "Test" };
var myClassDto = _objectMapper.Map<MyClass, MyClassDto>(myClass);
myClassDto.Name.ShouldBe("BeforeMap Test AfterMap");
}
}

60
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperlyModule_Basic_Tests.cs

@ -0,0 +1,60 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Mapperly.SampleClasses;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Mapperly;
public class AbpMapperlyModule_Basic_Tests : AbpIntegratedTest<MapperlyTestModule>
{
private readonly IObjectMapper _objectMapper;
public AbpMapperlyModule_Basic_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
}
[Fact]
public void Should_Replace_IAutoObjectMappingProvider()
{
Assert.True(ServiceProvider.GetRequiredService<IAutoObjectMappingProvider>() is MapperlyAutoObjectMappingProvider);
}
[Fact]
public void Should_Map_Objects_With_AutoMap_Attributes()
{
var dto = _objectMapper.Map<MyEntity, MyEntityDto>(new MyEntity { Number = 42 });
dto.Number.ShouldBe(42);
}
[Fact]
public void Should_Map_Objects_With_Existing_Target_Object()
{
var dto = new MyEntityDto {Id = Guid.Empty, Number = 42};
_objectMapper.Map<MyEntity, MyEntityDto>(new MyEntity { Id = Guid.NewGuid(), Number = 43 }, dto);
dto.Number.ShouldBe(43);
dto.Id.ShouldNotBe(Guid.Empty);
}
[Fact]
public void Should_Map_Enum()
{
var dto = _objectMapper.Map<MyEnum, MyEnumDto>(MyEnum.Value3);
dto.ShouldBe(MyEnumDto.Value2); //Value2 is same as Value3
}
[Fact]
public void Should_Throw_Exception_If_Mapper_Is_Not_Found()
{
var exception = Assert.Throws<AbpException>(() =>_objectMapper.Map<MyEntity, MyClassDto>(new MyEntity()));
exception.Message.ShouldBe("No " +
"Volo.Abp.Mapperly.IAbpMapperlyMapper<Volo.Abp.Mapperly.SampleClasses.MyEntity,Volo.Abp.Mapperly.MyClassDto> or " +
"Volo.Abp.Mapperly.IAbpReverseMapperlyMapper<Volo.Abp.Mapperly.SampleClasses.MyEntity,Volo.Abp.Mapperly.MyClassDto>" +
" was found");
}
}

191
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperlyModule_Specific_ObjectMapper_Tests.cs

@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Mapperly.SampleClasses;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Mapperly;
public class AbpMapperlyModule_Specific_ObjectMapper_Tests : AbpIntegratedTest<MapperlyTestModule>
{
private readonly IObjectMapper _objectMapper;
public AbpMapperlyModule_Specific_ObjectMapper_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
}
[Fact]
public void Should_Use_Specific_Object_Mapper_If_Registered()
{
var dto = _objectMapper.Map<MyEntity, MyEntityDto2>(new MyEntity { Number = 42 });
dto.Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
}
[Fact]
public void Specific_Object_Mapper_Should_Be_Used_For_Collections_If_Registered()
{
// IEnumerable
_objectMapper.Map<IEnumerable<MyEntity>, IEnumerable<MyEntityDto2>>(new List<MyEntity>()
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var destination = new List<MyEntityDto2>()
{
new MyEntityDto2 { Number = 44 }
};
var returnIEnumerable = _objectMapper.Map<IEnumerable<MyEntity>, IEnumerable<MyEntityDto2>>(
new List<MyEntity>()
{
new MyEntity { Number = 42 }
}, destination);
returnIEnumerable.First().Number.ShouldBe(43);
ReferenceEquals(destination, returnIEnumerable).ShouldBeTrue();
// ICollection
_objectMapper.Map<ICollection<MyEntity>, ICollection<MyEntityDto2>>(new List<MyEntity>()
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var returnICollection = _objectMapper.Map<ICollection<MyEntity>, ICollection<MyEntityDto2>>(
new List<MyEntity>()
{
new MyEntity { Number = 42 }
}, destination);
returnICollection.First().Number.ShouldBe(43);
ReferenceEquals(destination, returnICollection).ShouldBeTrue();
// Collection
_objectMapper.Map<Collection<MyEntity>, Collection<MyEntityDto2>>(new Collection<MyEntity>()
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var destination2 = new Collection<MyEntityDto2>()
{
new MyEntityDto2 { Number = 44 }
};
var returnCollection = _objectMapper.Map<Collection<MyEntity>, Collection<MyEntityDto2>>(
new Collection<MyEntity>()
{
new MyEntity { Number = 42 }
}, destination2);
returnCollection.First().Number.ShouldBe(43);
ReferenceEquals(destination2, returnCollection).ShouldBeTrue();
// IList
_objectMapper.Map<IList<MyEntity>, IList<MyEntityDto2>>(new List<MyEntity>()
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var returnIList = _objectMapper.Map<IList<MyEntity>, IList<MyEntityDto2>>(
new List<MyEntity>()
{
new MyEntity { Number = 42 }
}, destination);
returnIList.First().Number.ShouldBe(43);
ReferenceEquals(destination, returnIList).ShouldBeTrue();
// List
_objectMapper.Map<List<MyEntity>, List<MyEntityDto2>>(new List<MyEntity>()
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var returnList = _objectMapper.Map<List<MyEntity>, List<MyEntityDto2>>(
new List<MyEntity>()
{
new MyEntity { Number = 42 }
}, destination);
returnList.First().Number.ShouldBe(43);
ReferenceEquals(destination, returnList).ShouldBeTrue();
// Array
_objectMapper.Map<MyEntity[], MyEntityDto2[]>(new MyEntity[]
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var destinationArray = new MyEntityDto2[]
{
new MyEntityDto2 { Number = 40 }
};
var returnArray = _objectMapper.Map<MyEntity[], MyEntityDto2[]>(new MyEntity[]
{
new MyEntity { Number = 42 }
}, destinationArray);
returnArray.First().Number.ShouldBe(43);
// array should not be changed. Same as Mapperly.
destinationArray.First().Number.ShouldBe(40);
ReferenceEquals(returnArray, destinationArray).ShouldBeFalse();
}
[Fact]
public void Specific_Object_Mapper_Should_Support_Multiple_IObjectMapper_Interfaces()
{
var myEntityDto2 = _objectMapper.Map<MyEntity, MyEntityDto2>(new MyEntity { Number = 42 });
myEntityDto2.Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
var myEntity = _objectMapper.Map<MyEntityDto2, MyEntity>(new MyEntityDto2 { Number = 42 });
myEntity.Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
// IEnumerable
_objectMapper.Map<IEnumerable<MyEntity>, IEnumerable<MyEntityDto2>>(new List<MyEntity>()
{
new MyEntity { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
_objectMapper.Map<IEnumerable<MyEntityDto2>, IEnumerable<MyEntity>>(new List<MyEntityDto2>()
{
new MyEntityDto2 { Number = 42 }
}).First().Number.ShouldBe(43); //MyEntityToMyEntityDto2Mapper adds 1 to number of the source.
}
[Fact]
public void Should_Use_Destination_Object_Constructor_If_Available()
{
var id = Guid.NewGuid();
var dto = _objectMapper.Map<MyEntity, MyEntityDtoWithMappingMethods>(new MyEntity { Number = 42, Id = id });
dto.Key.ShouldBe(id);
dto.No.ShouldBe(42);
}
[Fact]
public void Should_Use_Destination_Object_MapFrom_Method_If_Available()
{
var id = Guid.NewGuid();
var dto = new MyEntityDtoWithMappingMethods();
_objectMapper.Map(new MyEntity { Number = 42, Id = id }, dto);
dto.Key.ShouldBe(id);
dto.No.ShouldBe(42);
}
[Fact]
public void Should_Use_Source_Object_Method_If_Available_To_Create_New_Object()
{
var id = Guid.NewGuid();
var entity = _objectMapper.Map<MyEntityDtoWithMappingMethods, MyEntity>(new MyEntityDtoWithMappingMethods { Key = id, No = 42 });
entity.Id.ShouldBe(id);
entity.Number.ShouldBe(42);
}
[Fact]
public void Should_Use_Source_Object_Method_If_Available_To_Map_Existing_Object()
{
var id = Guid.NewGuid();
var entity = new MyEntity();
_objectMapper.Map(new MyEntityDtoWithMappingMethods { Key = id, No = 42 }, entity);
entity.Id.ShouldBe(id);
entity.Number.ShouldBe(42);
}
}

68
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpMapperly_Dependency_Injection_Tests.cs

@ -0,0 +1,68 @@
using System;
using Riok.Mapperly.Abstractions;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Mapperly;
public class MyDIClass
{
public string Id { get; set; }
public DateTime Birthday { get; set; }
}
public class MyDIClassDto
{
public string Id { get; set; }
public DateTime Birthday { get; set; }
}
public class BirthdayCalculatorService : ITransientDependency
{
public DateTime Birthday => DateTime.Parse("2025-01-01");
}
[Mapper]
public partial class MyDIClassMapper : MapperBase<MyDIClass, MyDIClassDto>
{
private readonly BirthdayCalculatorService _birthdayCalculatorService;
public MyDIClassMapper(BirthdayCalculatorService birthdayCalculatorService)
{
_birthdayCalculatorService = birthdayCalculatorService;
}
public override partial MyDIClassDto Map(MyDIClass source);
public override partial void Map(MyDIClass source, MyDIClassDto destination);
public override void AfterMap(MyDIClass source, MyDIClassDto destination)
{
destination.Birthday = _birthdayCalculatorService.Birthday;
}
}
public class AbpMapperly_Dependency_Injection_Tests : AbpIntegratedTest<MapperlyTestModule>
{
private readonly IObjectMapper _objectMapper;
private readonly BirthdayCalculatorService _birthdayCalculatorService;
public AbpMapperly_Dependency_Injection_Tests()
{
_objectMapper = GetRequiredService<IObjectMapper>();
_birthdayCalculatorService = GetRequiredService<BirthdayCalculatorService>();
}
[Fact]
public void DI_Test()
{
var myClass = new MyDIClass { Id = "1", Birthday = DateTime.Now };
var myClassDto = _objectMapper.Map<MyDIClass, MyDIClassDto>(myClass);
myClassDto.Birthday.ShouldBe(_birthdayCalculatorService.Birthday);
}
}

86
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/AbpReverseMapperly_Tests.cs

@ -0,0 +1,86 @@
using Microsoft.Extensions.DependencyInjection;
using Riok.Mapperly.Abstractions;
using Shouldly;
using Volo.Abp.ObjectMapping;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Mapperly;
public class MyReverseClass
{
public string Id { get; set; }
public string Name { get; set; }
}
public class MyReverseClassDto
{
public string Id { get; set; }
public string Name { get; set; }
}
[Mapper]
public partial class MyReverseClassMapper : TwoWayMapperBase<MyReverseClass, MyReverseClassDto>
{
public override partial MyReverseClassDto Map(MyReverseClass source);
public override partial void Map(MyReverseClass source, MyReverseClassDto destination);
public override partial MyReverseClass ReverseMap(MyReverseClassDto destination);
public override partial void ReverseMap(MyReverseClassDto destination, MyReverseClass source);
public override void BeforeReverseMap(MyReverseClassDto destination)
{
destination.Name = "BeforeReverseMap " + destination.Name;
}
public override void AfterReverseMap(MyReverseClassDto destination, MyReverseClass source)
{
source.Name = destination.Name + " AfterReverseMap";
}
}
public class AbpReverseMapperly_Tests : AbpIntegratedTest<MapperlyTestModule>
{
private readonly IObjectMapper _objectMapper;
public AbpReverseMapperly_Tests()
{
_objectMapper = ServiceProvider.GetRequiredService<IObjectMapper>();
}
[Fact]
public void Map_Test()
{
var myClass = new MyReverseClass { Id = "1", Name = "Test" };
var myClassDto = _objectMapper.Map<MyReverseClass, MyReverseClassDto>(myClass);
myClassDto.Name.ShouldBe("Test");
myClass.Id = "2";
myClass.Name = "Test2";
_objectMapper.Map<MyReverseClass, MyReverseClassDto>(myClass, myClassDto);
myClassDto.Id.ShouldBe("2");
myClassDto.Name.ShouldBe("Test2");
}
[Fact]
public void ReverseMap_Test()
{
var myClassDto = new MyReverseClassDto { Id = "1", Name = "Test" };
var myClass = _objectMapper.Map<MyReverseClassDto, MyReverseClass>(myClassDto);
myClass.Name.ShouldBe("BeforeReverseMap Test AfterReverseMap");
myClassDto.Id = "2";
myClassDto.Name = "Test2";
_objectMapper.Map<MyReverseClassDto, MyReverseClass>(myClassDto, myClass);
myClass.Id.ShouldBe("2");
myClass.Name.ShouldBe("BeforeReverseMap Test2 AfterReverseMap");
}
}

13
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/MapperlyTestModule.cs

@ -0,0 +1,13 @@
using Volo.Abp.Modularity;
using Volo.Abp.ObjectExtending;
namespace Volo.Abp.Mapperly;
[DependsOn(
typeof(AbpMapperlyModule),
typeof(AbpObjectExtendingTestModule)
)]
public class MapperlyTestModule : AbpModule
{
}

44
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MapperlyMappers.cs

@ -0,0 +1,44 @@
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
using Volo.Abp.Mapperly.SampleClasses;
using Volo.Abp.ObjectExtending.TestObjects;
[Mapper]
public partial class MyEntityMapper : MapperBase<MyEntity, MyEntityDto>
{
public override partial MyEntityDto Map(MyEntity source);
public override partial void Map(MyEntity source, MyEntityDto destination);
}
[Mapper]
public partial class MyEnumMapper : MapperBase<MyEnum, MyEnumDto>
{
public override partial MyEnumDto Map(MyEnum source);
public override void Map(MyEnum source, MyEnumDto destination)
{
destination = Map(source);
}
}
[Mapper]
[MapExtraProperties(IgnoredProperties = ["CityName"])]
public partial class ExtensibleTestPersonMapper : MapperBase<ExtensibleTestPerson, ExtensibleTestPersonDto>
{
public override partial ExtensibleTestPersonDto Map(ExtensibleTestPerson source);
public override partial void Map(ExtensibleTestPerson source, ExtensibleTestPersonDto destination);
}
[Mapper]
[MapExtraProperties(MapToRegularProperties = true)]
public partial class ExtensibleTestPersonWithRegularPropertiesDtoMapper : MapperBase<ExtensibleTestPerson, ExtensibleTestPersonWithRegularPropertiesDto>
{
[MapperIgnoreTarget(nameof(ExtensibleTestPersonWithRegularPropertiesDto.Name))]
[MapperIgnoreTarget(nameof(ExtensibleTestPersonWithRegularPropertiesDto.Age))]
[MapperIgnoreTarget(nameof(ExtensibleTestPersonWithRegularPropertiesDto.IsActive))]
public override partial ExtensibleTestPersonWithRegularPropertiesDto Map(ExtensibleTestPerson source);
public override partial void Map(ExtensibleTestPerson source, ExtensibleTestPersonWithRegularPropertiesDto destination);
}

10
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntity.cs

@ -0,0 +1,10 @@
using System;
namespace Volo.Abp.Mapperly.SampleClasses;
public class MyEntity
{
public Guid Id { get; set; }
public int Number { get; set; }
}

10
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityDto.cs

@ -0,0 +1,10 @@
using System;
namespace Volo.Abp.Mapperly.SampleClasses;
public class MyEntityDto
{
public Guid Id { get; set; }
public int Number { get; set; }
}

10
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityDto2.cs

@ -0,0 +1,10 @@
using System;
namespace Volo.Abp.Mapperly.SampleClasses;
public class MyEntityDto2
{
public Guid Id { get; set; }
public int Number { get; set; }
}

43
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityDtoWithMappingMethods.cs

@ -0,0 +1,43 @@
using System;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.Mapperly.SampleClasses;
//TODO: Move tests to Volo.Abp.ObjectMapping test project
public class MyEntityDtoWithMappingMethods : IMapFrom<MyEntity>, IMapTo<MyEntity>
{
public Guid Key { get; set; }
public int No { get; set; }
public MyEntityDtoWithMappingMethods()
{
}
public MyEntityDtoWithMappingMethods(MyEntity entity)
{
MapFrom(entity);
}
public void MapFrom(MyEntity source)
{
Key = source.Id;
No = source.Number;
}
MyEntity IMapTo<MyEntity>.MapTo()
{
return new MyEntity
{
Id = Key,
Number = No
};
}
void IMapTo<MyEntity>.MapTo(MyEntity destination)
{
destination.Id = Key;
destination.Number = No;
}
}

39
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEntityToMyEntityDto2Mapper.cs

@ -0,0 +1,39 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.ObjectMapping;
namespace Volo.Abp.Mapperly.SampleClasses;
public class MyEntityToMyEntityDto2Mapper : IObjectMapper<MyEntity, MyEntityDto2>, IObjectMapper<MyEntityDto2, MyEntity>, ITransientDependency
{
public MyEntityDto2 Map(MyEntity source)
{
return new MyEntityDto2
{
Id = source.Id,
Number = source.Number + 1
};
}
public MyEntityDto2 Map(MyEntity source, MyEntityDto2 destination)
{
destination.Id = source.Id;
destination.Number = source.Number + 1;
return destination;
}
public MyEntity Map(MyEntityDto2 source)
{
return new MyEntity
{
Id = source.Id,
Number = source.Number + 1
};
}
public MyEntity Map(MyEntityDto2 source, MyEntity destination)
{
destination.Id = source.Id;
destination.Number = source.Number + 1;
return destination;
}
}

8
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEnum.cs

@ -0,0 +1,8 @@
namespace Volo.Abp.Mapperly.SampleClasses;
public enum MyEnum
{
Value1 = 1,
Value2,
Value3
}

9
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyEnumDto.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.Mapperly.SampleClasses;
public enum MyEnumDto
{
Value1 = 2,
Value2,
Value3,
Value
}

10
framework/test/Volo.Abp.Mapperly.Tests/Volo/Abp/Mapperly/SampleClasses/MyNotMappedDto.cs

@ -0,0 +1,10 @@
using System;
namespace Volo.Abp.Mapperly.SampleClasses;
public class MyNotMappedDto
{
public Guid Id { get; set; }
public int Number { get; set; }
}

1
nupkg/common.ps1

@ -221,6 +221,7 @@ $projects = (
"framework/src/Volo.Abp.Ldap",
"framework/src/Volo.Abp.Localization.Abstractions",
"framework/src/Volo.Abp.MailKit",
"framework/src/Volo.Abp.Mapperly",
"framework/src/Volo.Abp.Maui.Client",
"framework/src/Volo.Abp.Localization",
"framework/src/Volo.Abp.MemoryDb",

Loading…
Cancel
Save