Browse Source
Merge pull request #20829 from abpframework/DefaultObjectMapper
Optimize the way to get `Map` method through reflection.
pull/20854/head
Engincan VESKE
2 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with
70 additions and
7 deletions
-
framework/src/Volo.Abp.ObjectMapping/Volo/Abp/ObjectMapping/DefaultObjectMapper.cs
-
framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/AbpAutoMapperModule_Specific_ObjectMapper_Tests.cs
-
framework/test/Volo.Abp.AutoMapper.Tests/Volo/Abp/AutoMapper/SampleClasses/MyEntityToMyEntityDto2Mapper.cs
|
|
|
@ -142,13 +142,39 @@ public class DefaultObjectMapper : IObjectMapper, ITransientDependency |
|
|
|
cacheKey, |
|
|
|
_ => |
|
|
|
{ |
|
|
|
return specificMapper |
|
|
|
var methods = specificMapper |
|
|
|
.GetType() |
|
|
|
.GetMethods() |
|
|
|
.First(x => |
|
|
|
x.Name == nameof(IObjectMapper<object, object>.Map) && |
|
|
|
x.GetParameters().Length == (destination == null ? 1 : 2) |
|
|
|
); |
|
|
|
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) |
|
|
|
.Where(x => x.Name == nameof(IObjectMapper<object, object>.Map)) |
|
|
|
.Where(x => |
|
|
|
{ |
|
|
|
var parameters = x.GetParameters(); |
|
|
|
if (destination == null && parameters.Length != 1 || |
|
|
|
destination != null && parameters.Length != 2 || |
|
|
|
parameters[0].ParameterType != sourceArgumentType) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
return destination == null || parameters[1].ParameterType == destinationArgumentType; |
|
|
|
}) |
|
|
|
.ToList(); |
|
|
|
|
|
|
|
if (methods.IsNullOrEmpty()) |
|
|
|
{ |
|
|
|
throw new AbpException($"Could not find a method named '{nameof(IObjectMapper<object, object>.Map)}'" + |
|
|
|
$" with parameters({(destination == null ? sourceArgumentType.ToString() : sourceArgumentType + "," + destinationArgumentType)})" + |
|
|
|
$" in the type '{mapperType}'."); |
|
|
|
} |
|
|
|
|
|
|
|
if (methods.Count > 1) |
|
|
|
{ |
|
|
|
throw new AbpException($"Found more than one method named '{nameof(IObjectMapper<object, object>.Map)}'" + |
|
|
|
$" with parameters({(destination == null ? sourceArgumentType.ToString() : sourceArgumentType + "," + destinationArgumentType)})" + |
|
|
|
$" in the type '{mapperType}'."); |
|
|
|
} |
|
|
|
|
|
|
|
return methods.First(); |
|
|
|
} |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
@ -130,6 +130,27 @@ public class AbpAutoMapperModule_Specific_ObjectMapper_Tests : AbpIntegratedTest |
|
|
|
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() |
|
|
|
{ |
|
|
|
|
|
|
|
@ -3,7 +3,7 @@ using Volo.Abp.ObjectMapping; |
|
|
|
|
|
|
|
namespace Volo.Abp.AutoMapper.SampleClasses; |
|
|
|
|
|
|
|
public class MyEntityToMyEntityDto2Mapper : IObjectMapper<MyEntity, MyEntityDto2>, ITransientDependency |
|
|
|
public class MyEntityToMyEntityDto2Mapper : IObjectMapper<MyEntity, MyEntityDto2>, IObjectMapper<MyEntityDto2, MyEntity>, ITransientDependency |
|
|
|
{ |
|
|
|
public MyEntityDto2 Map(MyEntity source) |
|
|
|
{ |
|
|
|
@ -20,4 +20,20 @@ public class MyEntityToMyEntityDto2Mapper : IObjectMapper<MyEntity, MyEntityDto2 |
|
|
|
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; |
|
|
|
} |
|
|
|
} |
|
|
|
|