0

I have the below models in Asp.net Core Web API project.

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; }
    }

I have the below model in Data Access Layer:

 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; }

    }

I have below Automapper profile 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
                 }
             });
    }
}

The above code is working fine as I'm using AfterMap. However, is there any better way of writing this rather than using AfterMap? AfterMap feels like I'm writing mapping code myself rather than using Automapper in a better manner.

I've also tried a different approach to nested object mapping from Automapper documentation. However, it is not working in my case and I'm getting one or the other error.

Edit:

I have tried below mapping as well, but the TestExamReport objects are null and only PatientKey is having value.

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();
sarrow
  • 3
  • 2
  • 2
    See [this](https://docs.automapper.org/en/latest/Flattening.html) and [this](https://docs.automapper.org/en/latest/Reverse-Mapping-and-Unflattening.html). – Lucian Bargaoanu Jun 02 '21 at 14:48
  • Already tried both of these, not working. Either I get the error or the Objects in TestExamReport are null except PatientKey. If you see both the models, I'm mapping the data access layer model to the properties of the BaselineOP/BaselineOR that are three-level deep. – sarrow Jun 02 '21 at 15:39
  • The level of nesting is irrelevant as long as you have all the nested maps. Start with smth simple and work your way up. – Lucian Bargaoanu Jun 02 '21 at 15:42
  • @LucianBargaoanu See the edit. Thanks. – sarrow Jun 02 '21 at 16:20

1 Answers1

0

I've resolved the issue from this and this.

Below is my sample code to make it work:

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();

The only problem I'm facing right now with the above code is that if all the property values are null, for example, for BaselineOP, I want to set it to null. I need to explore Automapper more for that.

EDIT:

After going through this post, I was able to mark BaselineOP as null if all its properties are null. It is working.

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();
sarrow
  • 3
  • 2