Mapping backwards ?
michelbieleveld opened this issue · 3 comments
I have seen two posts about asking why the mapping is performed backwards and I think I am also seeing something unexpected;
using System.Linq.Expressions;
using AutoMapper;
using AutoMapper.Extensions.ExpressionMapping;
using NUnit.Framework;
namespace MyTest;
[TestFixture]
public class GroupAggregateTest
{
public record GroupId(Guid Guid);
public class Group
{
public GroupId Id { get; set; }
}
public class GroupDto
{
public string Id { get; set; }
}
[Test]
public void ListGroups()
{
var configuration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Group, GroupDto>(MemberList.Destination)
.ForMember(dest => dest.Id,
opt =>
opt.MapFrom(src => src.Id.Guid.ToString()));
cfg.CreateMap<GroupDto, Group>(MemberList.Source)
.ForMember(dest => dest.Id, opt =>
opt.MapFrom(src => new GroupId(Guid.Parse(src.Id))));
cfg.AddExpressionMapping();
});
var mapper = configuration.CreateMapper();
var executionPlan = configuration.BuildExecutionPlan(typeof(GroupDto), typeof(Group));
Expression<Func<GroupDto, bool>> expr = dto => dto.Id == "07fbbbd5-8cd2-4228-9fc5-2363419c9405";
var exprMapped = mapper.MapExpression<Expression<Func<Group, bool>>>(expr);
Expression<Func<Group, bool>> exprExpected = dto => dto.Id == new GroupId(Guid.Parse("07fbbbd5-8cd2-4228-9fc5-2363419c9405"));
Assert.AreEqual(exprExpected,exprMapped);
}
}
Now the output that I would expect when mapping from DTO to domain object is that the expression is completely defined in the domain object language meaning that just like in the mapping above the string is converted to the strongly typed GroupId. However, that is not what occurs, due to the reverse mapping I think the domain object is translated to the dto object for the comparison as can be seen here;
The expression converts the GroupId to string instead of what would be expected changing the string to the GroupId. This matters when EF core is then used to yet another type mapping to the database. In case of the string it would be wrong.
Am I doing something wrong or unexpected ? Why would we not use the forward mapping from Dto to Domain and then apply the function as defined in the mapper on the string ?
Your initial is Expression<Func<GroupDto, bool>> expr = dto => dto.Id == "07fbbbd5-8cd2-4228-9fc5-2363419c9405";
Based on opt.MapFrom(src => src.Id.Guid.ToString()));
dto.Id
becomes dto.Id.Guid.ToString()
. The string did not change as expected.
May help to look at the code?
Yes, that is what is happening but not what would have been expected as we are going from GroupDto to Dto. In that case what would been expected that the string is converted to GroupId(guid) and then compared with the Id which is already of type GroupId, similar what would happens normally in automapper. I understand we have different opinion on what is "expected" ;-) but is there an easy way to occur what I would want that the string converts and not the id ?
Always room for improvement. Best to make the use case clear - including a PR showing the better approach.