1

我在使用 ASP.NET Core 2.2 和 Automapper 9.0.0 时遇到以下问题:

我有一个映射到 dto 的实体,这很好用。该实体内部还有一些实体。这些不能展平,因为我们的客户也需要它们。然而,在这些嵌套实体中有一个属性需要额外的映射。

在重叠实体的 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- 在 Profile 类中使用“AfterMap”(结果:DisplayDesc = null)

CreateMap<TblDatOperationalHUTrace, PalletResult>()
            .ForMember(dest => dest.TransCode, act => act.MapFrom((src, _, transactionCode, ctx) =>
                ctx.Mapper.Map<TblLstCode, 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, act => act.MapFrom((src, _, transactionCode, ctx) =>
            ctx.Mapper.Map<TblLstCode, TransactionCodeResult>(src.TransCode, 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, dest, 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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                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.",
                ex,
                AutoMapper.TypePair,
                TypeMap,
                PropertyMap);

            return null;
        }
        afterFunction.Invoke(src, typeMapDestination, 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
4

1 回答 1

0

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

我将 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

然后它就像它应该的那样工作。

于 2020-01-09T11:11:50.623 回答