用于嵌套映射的 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();
我在 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。
编辑:
完成
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();