Альтернатива Automapper Aftermap для вложенного сопоставления

У меня есть следующие модели в проекте 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:

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 имеют значение null, и только 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();

person sarrow    schedule 02.06.2021    source источник
comment
См. это и это.   -  person Lucian Bargaoanu    schedule 02.06.2021
comment
Уже попробовал оба из них, не работает. Либо я получаю сообщение об ошибке, либо объекты в TestExamReport имеют значение null, кроме PatientKey. Если вы видите обе модели, я сопоставляю модель уровня доступа к данным со свойствами BaselineOP/BaselineOR, которые имеют трехуровневую глубину.   -  person sarrow    schedule 02.06.2021
comment
Уровень вложенности не имеет значения, если у вас есть все вложенные карты. Начните с чего-то простого и продвигайтесь вверх.   -  person Lucian Bargaoanu    schedule 02.06.2021
comment
@LucianBargaoanu Смотрите правку. Спасибо.   -  person sarrow    schedule 02.06.2021


Ответы (1)


Я решил проблему из этого и это.

Ниже приведен пример кода, чтобы заставить его работать:

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.

ИЗМЕНИТЬ:

После прохождения этот пост, я смог пометить BaselineOP как null, если все его свойства равны null. Это работает.

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();
person sarrow    schedule 03.06.2021
comment
docs.automapper.org/en/latest/ - person Lucian Bargaoanu; 03.06.2021
comment
@LucianBargaoanu, не могли бы вы пояснить на примере, как размещенная вами ссылка может быть полезна мне в моем случае? - person sarrow; 03.06.2021