自动映射器:使用参数

使用ASP.NET Core 2.2和Automapper 9.0.0时出现以下问题:

我有一个映射到dto的Entity,效果很好。在该实体内部还有一些实体。这些不能被扁平化,因为我们的客户也需要它们。但是,在这些嵌套实体中有一个属性需要附加映射。

在重叠实体的Profile类中,我这样做:

public class OperationalToPalletResultProfile : Profile
{
    public OperationalToPalletResultProfile()
    {
        string lang = null;

        CreateMap<TblDatOperationalHUTrace,PalletResult>()
            .ForMember(dest => dest.TransCode,act => act.MapFrom((src,_,transactionCode,ctx) =>
                ctx.Mapper.Map<TblLstCode,TransactionCodeResult>(src.TransCode)));
    }
}

这有效地将TblLstCode正确映射到TransactionCodeResult。但是,TransactionCodeResult的“ DisplayDesc”属性仍然为空...

注意:“ lang”属性是通过“ ProjectTo”方法设置的:

var values = await query
        .Take(5000)
        .ProjectTo<PalletResult>(mapper.ConfigurationProvider,new { lang = language })
        .ToListAsync()
        .ConfigureAwait(false);

我尝试过:

1-在P​​rofile类中使用“ AfterMap”(结果:DisplayDesc = null)

CreateMap<TblDatOperationalHUTrace,TransactionCodeResult>(src.TransCode,opt =>
                    opt.AfterMap((source,destination) =>
                        destination.DisplayDesc = $"[{destination.ShortName}] {destination.DescToLanguageDesc(destination,lang)}"))))

注意:DescToLanguageDesc是一个可以通过反射在实体中找到属性的函数(此方法有效,且不属于问题的一部分)

2-创建要在子实体的配置文件中使用的IMappingaction(结果:DisplayDesc = null)

public class TransactionCodeTranslation : IMappingaction<TblLstCode,TransactionCodeResult>
{
    private readonly IHttpContextaccessor httpContextaccessor;

    public TransactionCodeTranslation(IHttpContextaccessor httpContextaccessor)
    {
        this.httpContextaccessor = httpContextaccessor;
    }

    public void Process(TblLstCode source,TransactionCodeResult destination,ResolutionContext context)
    {
        //Get language from httpContext - this works correctly

        destination.DisplayDesc = $"[{source.ShortName}] {source.DescToLanguageDesc(source,language)}";
    }
}


public class TransactionCodeProfile : Profile
{
    public TransactionCodeProfile()
    {
        string language = string.Empty;

        CreateMap<TblLstCode,TransactionCodeResult>()
            .AfterMap<TransactionCodeTranslation>();
    }
}

这不起作用。但是,如果我直接使用选项2:

var tc = await codeRepo.TableNoTracking.FirstOrDefaultAsync(x => x.ShortName == "[something]").ConfigureAwait(false);
var transactionCode = mapper.Map<TblLstCode,TransactionCodeResult>(tc);

然后它可以正常工作!但这意味着我将不得不循环执行结果并再次映射结果中的每个对象...

有没有办法像选项1一样?

谢谢!

编辑1:

我应Lucian Bargaoanu的要求添加了一个BuildExecutionPlan:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<TblDatOperationalHUTrace,PalletResult>()
        .ForMember(dest => dest.TransCode,ctx) =>
            ctx.Mapper.Map<TblLstCode,opt =>
                opt.AfterMap((source,destination) =>
                    destination.DisplayDesc = $"[{destination.ShortName}] {destination.DescToLanguageDesc(destination,language)}"))));

    cfg.CreateMap<TblLstCode,TransactionCodeResult>()
        .AfterMap<TransactionCodeTranslation>();
});

var expression = config.BuildExecutionPlan(typeof(TblDatOperationalHUTrace),typeof(PalletResult));
var expression2 = config.BuildExecutionPlan(typeof(TblLstCode),typeof(TransactionCodeResult));

表达结果:

(src,dest,ctxt) =>
{
PalletResult typeMapDestination;
return (src == null)
    ? null
    : {
        typeMapDestination = dest ?? new PalletResult();
        try
        {
            var resolvedValue = mappingFunction.Invoke(
                src,typeMapDestination,typeMapDestination.TransCode,ctxt);
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.TransCode = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",ex,AutoMapper.TypePair,TypeMap,PropertyMap);

            return null;
        }            

        return typeMapDestination;
    };

}

结果表达式2:

(src,ctxt) =>
{
TransactionCodeResult typeMapDestination;
return (src == null)
    ? null
    : {
        typeMapDestination = dest ?? new TransactionCodeResult();
        try
        {
            var resolvedValue = ((src == null) || false) ? default(int) : src.Id;
            typeMapDestination.Id = resolvedValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);
            return default(int);
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? null : src.ShortName;
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.ShortName = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return null;
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? default(int) : src.CodeTypeId;
            typeMapDestination.CodeTypeId = resolvedValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return default(int);
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? null : src.descLC;
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.DescLC = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return null;
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? null : src.descEN;
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.DescEN = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return null;
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? null : src.descFR;
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.DescFR = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return null;
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? null : src.descGE;
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.DescGE = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return null;
        }
        try
        {
            var resolvedValue = ((src == null) || false) ? null : src.descNL;
            var propertyValue = (resolvedValue == null) ? null : resolvedValue;
            typeMapDestination.DescNL = propertyValue;
        }
        catch (Exception ex)
        {
            throw new AutoMapperMappingException(
                "Error mapping types.",PropertyMap);

            return null;
        }
        afterFunction.Invoke(src,ctxt);

        return typeMapDestination;
    };

}

编辑2:

好的,我实际上找到了解决方案。我无缘无故地把事情复杂化了...

我将OperationalToPalletResultProfile更改为:

public class OperationalToPalletResultProfile : Profile
{
    public OperationalToPalletResultProfile()
    {
        CreateMap<TblDatOperationalHUTrace,PalletResult>();
    }
}

TransactionCodeProfile保持不变:

public class TransactionCodeProfile : Profile
{
    public TransactionCodeProfile()
    {
        CreateMap<TblLstCode,TransactionCodeResult>()
            .AfterMap<TransactionCodeTranslation>();
    }
}

然后在我使用映射的地方,我对此进行了更改:

//results as TblDatOperationalHUTrace
var queryresult = await query
    .Take(5000)
    //.ProjectTo<PalletResult>(mapper.ConfigurationProvider) Don't do the mapping here anymore
    .ToListAsync()
    .ConfigureAwait(false);

//Map results to PalletResult
var values = mapper.Map<List<TblDatOperationalHUTrace>,List<PalletResult>>(queryresult); //Do the mapping here
snoopy717 回答:自动映射器:使用参数

好吧,我实际上自己找到了解决方案:

我将OperationalToPalletResultProfile更改为:

public class OperationalToPalletResultProfile : Profile
{
    public OperationalToPalletResultProfile()
    {
        CreateMap<TblDatOperationalHUTrace,PalletResult>();
    }
}

TransactionCodeProfile保持不变:

public class TransactionCodeProfile : Profile
{
    public TransactionCodeProfile()
    {
        CreateMap<TblLstCode,TransactionCodeResult>()
            .AfterMap<TransactionCodeTranslation>();
    }
}

然后在我使用映射的地方,我对此进行了更改:

//results as TblDatOperationalHUTrace
var queryresult = await query
    .Take(5000)
    //.ProjectTo<PalletResult>(mapper.ConfigurationProvider) Don't do the mapping here anymore
    .ToListAsync()
    .ConfigureAwait(false);

//Map results to PalletResult
var values = mapper.Map<List<TblDatOperationalHUTrace>,List<PalletResult>>(queryresult); //Do the mapping here

然后按预期的方式工作。

本文链接:https://www.f2er.com/2798970.html

大家都在问