用于嵌套映射的 Automapper Aftermap 替代方案

Automapper Aftermap alternative for Nested Mapping

我在 Asp.net Core Web API 项目中有以下模型。

public class TestExamReport
    {
        public string PatientKey { get; set; }

        public string OPDiagnosis { get; set; }

        public string ORDiagnosis { get; set; }

        public OPExam OPExamDetails { get; set; }

        public ORExam ORExamDetails { get; set; }

    }

     public class OPExam
    {
        public BaselineOP Baseline { get; set; }

        public CurrentOP Current { get; set; }
    }

    public class ORExam
    {
        public BaselineOR Baseline { get; set; }

        public CurrentOR Current { get; set; }
    }

    public class BaselineOP 
    {
        public string SeriesKey { get; set; }
        public DateTime SeriesDate { get; set; }
        public string ImagePath { get; set; }
        public DateTime? ReviewedOn { get; set; }
    }

    public class BaselineOR
    {
        public string SeriesKey { get; set; }
        public DateTime SeriesDate { get; set; }
        public string ImagePath { get; set; }
        public DateTime? ReviewedOn { get; set; }
    }

    public class CurrentOP : BaselineOP
    {
        public bool ThresholdFlag { get; set; }
    }
    
    public class CurrentOR : BaselineOR
    {
        public bool ThresholdFlag { get; set; }
    }

我在数据访问层中有以下模型:

 public class TestExamResult
    {
        public string Patientkey { get; set; }
        
        public string OPDiagnosis { get; set; }
        
        public string ORDiagnosis { get; set; }

        public string BaselineOPSeriesKey { get; set; }

        public DateTime BaselineOPSeriesDate { get; set; }

        public string BaselineOPImage { get; set; }

        public DateTime? BaselineOPReviewedOn { get; set; }

        public string CurrentOPSeriesKey { get; set; }

        public DateTime CurrentOPSeriesDate { get; set; }

        public string CurrentOPImage { get; set; }

        public DateTime? CurrentOPReviewedOn { get; set; }

        public bool CurrentOPThresholdFlag { get; set; }

        public string BaselineORSeriesKey { get; set; }

        public DateTime BaselineORSeriesDate { get; set; }

        public string BaselineORImage { get; set; }

        public DateTime? BaselineORReviewedOn { get; set; }

        public string CurrentORSeriesKey { get; set; }

        public DateTime CurrentORSeriesDate { get; set; }

        public string CurrentORImage { get; set; }

        public DateTime? CurrentORReviewedOn { get; set; }

        public bool CurrentORThresholdFlag { get; set; }

    }

我有以下 Automapper 配置文件 class:

public class PersonProfile : Profile
{
    public PersonProfile()
    {
       
           CreateMap<TestExamResult, TestExamReport>()
            .ForMember(dest => dest.OPExamDetails, src => src.Ignore())
            .ForMember(dest => dest.ORExamDetails, src => src.Ignore())
            .AfterMap((Src, Dest) =>
            Dest.OPExamDetails = new OPExam
            {
                Baseline = new BaselineOP()
                {
                    SeriesKey = Src.BaselineOPSeriesKey,
                    SeriesDate = Src.BaselineOPSeriesDate,
                    ImagePath = Src.BaselineOPImage,
                    ReviewedOn = Src.BaselineOPReviewedOn
                },
                Current = new CurrentOP()
                {
                    SeriesKey = Src.CurrentOPSeriesKey,
                    SeriesDate = Src.CurrentOPSeriesDate,
                    ImagePath = Src.CurrentOPImage,
                    ReviewedOn = Src.CurrentOPReviewedOn,
                    ThresholdFlag = Src.CurrentOPThresholdFlag
                }
            })
             .AfterMap((Src, Dest) =>
             Dest.ORExamDetails = new ORExam
             {
                 Baseline = new BaselineOR()
                 {
                     SeriesKey = Src.BaselineORSeriesKey,
                     SeriesDate = Src.BaselineORSeriesDate,
                     ImagePath = Src.BaselineORImage,
                     ReviewedOn = Src.BaselineORReviewedOn
                 },
                 Current = new CurrentOR()
                 {
                     SeriesKey = Src.CurrentORSeriesKey,
                     SeriesDate = Src.CurrentORSeriesDate,
                     ImagePath = Src.CurrentORImage,
                     ReviewedOn = Src.CurrentORReviewedOn,
                     ThresholdFlag = Src.CurrentORThresholdFlag
                 }
             });
    }
}

上面的代码在我使用 AfterMap 时工作正常。但是,有没有比使用 AfterMap 更好的写法? AfterMap 感觉我是在自己写映射代码,而不是以更好的方式使用 Automapper。

我还尝试了一种不同的方法来从 Automapper 文档中进行嵌套对象映射。但是,它在我的情况下不起作用,我遇到了一个或另一个错误。

编辑:

我也试过下面的映射,但是 TestExamReport 对象为空,只有 PatientKey 有价值。

CreateMap<TestExamResult, TestExamReport>();
                //Below two lines don't have impact, even 
                //If they are remove, objects are still null
                CreateMap<TestExamResult, OPExam>();
                CreateMap<TestExamResult, ORExam>();
                CreateMap<TestExamResult, BaselineOP>()
                    .ForMember(dest => dest.SeriesKey, src => src.MapFrom(y => y.BaselineOPSeriesKey))
                    .ForMember(dest => dest.SeriesDate, src => src.MapFrom(y => y.BaselineOPSeriesDate))
                    .ForMember(dest => dest.ImagePath, src => src.MapFrom(y => y.BaselineOPImage))
                    .ForMember(dest => dest.ReviewedOn, src => src.MapFrom(y => y.BaselineOPReviewedOn))
                    .ReverseMap();
                CreateMap<TestExamResult, CurrentOP>()
                    .ForMember(dest => dest.SeriesKey, src => src.MapFrom(y => y.CurrentOPSeriesKey))
                    .ForMember(dest => dest.SeriesDate, src => src.MapFrom(y => y.CurrentOPSeriesDate))
                    .ForMember(dest => dest.ImagePath, src => src.MapFrom(y => y.CurrentOPImage))
                    .ForMember(dest => dest.ReviewedOn, src => src.MapFrom(y => y.CurrentOPReviewedOn))
                    .ForMember(dest => dest.ThresholdFlag, src => src.MapFrom(y => y.CurrentOPThresholdFlag))
                    .ReverseMap();
                CreateMap<TestExamResult, BaselineOR>()
                   .ForMember(dest => dest.SeriesKey, src => src.MapFrom(y => y.BaselineORSeriesKey))
                   .ForMember(dest => dest.SeriesDate, src => src.MapFrom(y => y.BaselineORSeriesDate))
                   .ForMember(dest => dest.ImagePath, src => src.MapFrom(y => y.BaselineORImage))
                   .ForMember(dest => dest.ReviewedOn, src => src.MapFrom(y => y.BaselineORReviewedOn))
                   .ReverseMap();
                CreateMap<TestExamResult, CurrentOR>()
                    .ForMember(dest => dest.SeriesKey, src => src.MapFrom(y => y.CurrentORSeriesKey))
                    .ForMember(dest => dest.SeriesDate, src => src.MapFrom(y => y.CurrentORSeriesDate))
                    .ForMember(dest => dest.ImagePath, src => src.MapFrom(y => y.CurrentORImage))
                    .ForMember(dest => dest.ReviewedOn, src => src.MapFrom(y => y.CurrentORReviewedOn))
                    .ForMember(dest => dest.ThresholdFlag, src => src.MapFrom(y => y.CurrentORThresholdFlag))
                    .ReverseMap();

我已经解决了 this and this 的问题。

下面是我的示例代码以使其工作:

cfg.CreateMap<TestExamResult, BaselineOP>()
                .ForMember(d => d.SeriesKey, opt => opt.MapFrom(src => src.BaselineOPSeriesKey))
                .ForMember(d => d.SeriesDate, opt => opt.MapFrom(src => src.BaselineOPSeriesDate))
                .ForMember(d => d.ImagePath, opt => opt.MapFrom(src => src.BaselineOPImage))
                .ForMember(d => d.ReviewedOn, opt => opt.MapFrom(src => src.BaselineOPReviewedOn))
                .ReverseMap();
            cfg.CreateMap<TestExamResult, BaselineOR>()
                .ForMember(d => d.SeriesKey, opt => opt.MapFrom(src => src.BaselineORSeriesKey))
                .ForMember(d => d.SeriesDate, opt => opt.MapFrom(src => src.BaselineORSeriesDate))
                .ForMember(d => d.ImagePath, opt => opt.MapFrom(src => src.BaselineORImage))
                .ForMember(d => d.ReviewedOn, opt => opt.MapFrom(src => src.BaselineORReviewedOn))
                .ReverseMap();
            cfg.CreateMap<TestExamResult,OPExam>()
                .ForMember(d=>d.BaselineOP, opt => opt.MapFrom(src => src)).ReverseMap();
                cfg.CreateMap<TestExamResult,ORExam>()
                .ForMember(d=>d.BaselineOR, opt => opt.MapFrom(src => src)).ReverseMap();
            cfg.CreateMap<TestExamResult, TestExamReport>()
                .ForMember(d=>d.OPExam, opt => opt.MapFrom(src => src))
                .ForMember(d=>d.ORExam, opt => opt.MapFrom(src => src))
                .ReverseMap();

我现在面对上面代码的唯一问题是,如果所有 属性 值都为空,例如,对于 BaselineOP,我想将其设置为空。为此,我需要更多地探索 Automapper。

编辑:

完成 post 后,如果其所有属性均为空,我能够将 BaselineOP 标记为空。正在运行。

cfg.CreateMap<TestExamResult,OPExam>()
    .ForMember(d=>d.BaselineOP,  b => b.MapFrom((c, a, obj, context) => !string.IsNullOrEmpty(c.BaselineOPSeriesKey) ? context.Mapper.Map<BaselineOP>(c) : null))
    .ReverseMap();