You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免带ID属性及关联模型差异的继承DTO间代码重复

优化AutoMapper映射方案:减少DTO重复代码

问题背景

我有一个领域实体KycInformation,用两个DTO区分不同业务场景:

  • KycInformationDto:用于创建操作(无需ID属性)
  • KycInformationDetailDto:用于查询/更新操作(包含ID属性)

两者唯一区别:

  1. KycInformationDetailDto多了Id属性
  2. 集合Documents的元素类型从KycDocumentDto换成KycDocumentDetailDto

当前用AutoMapper做类型映射,想在保持DTO分离的前提下,减少代码重复,求最佳实现方案。

附现有代码:

// 领域实体
public class KycInformation : BaseEntity
{
    public required KycStatus Status { get; set; }
    public required RiskRating RiskRating { get; set; }
    public required AmlStatus AmlStatus { get; set; }
    public required SanctionsCheckStatus SanctionsCheckStatus { get; set; }
    public string? ComplianceNotes { get; set; }
    public string? ParentCompany { get; set; }

    public required Guid LegalEntityId { get; set; }
    public required LegalEntity LegalEntity { get; set; }

    public ICollection<KycDocument> Documents { get; set; } = new List<KycDocument>();

    public void AddDocument(KycDocument document) => Documents.Add(document);

    public void ClearDocuments() => Documents.Clear();
}

// 创建用DTO
public record KycInformationDto
{
    public required KycStatus Status { get; init; }
    public required RiskRating RiskRating { get; init; }
    public required AmlStatus AmlStatus { get; init; }
    public required SanctionsCheckStatus SanctionsCheckStatus { get; init; }
    public string? ComplianceNotes { get; init; }
    public string? ParentCompany { get; init; }

    public ICollection<KycDocumentDto> Documents { get; init; } = new List<KycDocumentDto>();

    private class Mapping : Profile
    {
        public Mapping()
        {
            CreateMap<KycInformation, KycInformationDto>();
            CreateMap<KycInformationDto, KycInformation>();
        }
    }
}

// 查询/更新用DTO
public record KycInformationDetailDto : KycInformationDto
{
    public required Guid Id { get; init; }

    public new ICollection<KycDocumentDetailDto> Documents { get; init; } = new List<KycDocumentDetailDto>();

    private class Mapping : Profile
    {
        public Mapping()
        {
            CreateMap<KycInformation, KycInformationDetailDto>();
            CreateMap<KycInformationDetailDto, KycInformation>();
        }
    }
}

// 文档基础DTO
public record KycDocumentDto
{
    public required string DocumentType { get; init; }
    public required string DocumentName { get; init; }
    public string? DocumentDescription { get; init; }
    public required string DocumentUrl { get; init; }

    private class Mapping : Profile
    {
        public Mapping()
        {
            CreateMap<KycDocument, KycDocumentDto>();
            CreateMap<KycDocumentDto, KycDocument>();
        }
    }
}

// 文档详情DTO
public record KycDocumentDetailDto : KycDocumentDto
{
    public required Guid Id { get; init; }

    private class Mapping : Profile
    {
        public Mapping()
        {
            CreateMap<KycDocument, KycDocumentDetailDto>();
            CreateMap<KycDocumentDetailDto, KycDocument>();
        }
    }
}

解决方案

1. 复用基础映射配置

AutoMapper支持继承映射,你可以让KycInformationDetailDto的映射继承KycInformationDto的配置,避免重复定义相同属性的映射规则。

调整KycInformationDetailDto的映射类:

private class Mapping : Profile
{
    public Mapping()
    {
        // 继承基础DTO的映射规则
        CreateMap<KycInformation, KycInformationDetailDto>()
            .IncludeBase<KycInformation, KycInformationDto>();
        // 反向映射同样继承
        CreateMap<KycInformationDetailDto, KycInformation>()
            .IncludeBase<KycInformationDto, KycInformation>();
        
        // Id属性会自动匹配BaseEntity的同名属性,无需额外配置
    }
}

同理处理KycDocumentDetailDto的映射:

private class Mapping : Profile
{
    public Mapping()
    {
        CreateMap<KycDocument, KycDocumentDetailDto>()
            .IncludeBase<KycDocument, KycDocumentDto>();
        CreateMap<KycDocumentDetailDto, KycDocument>()
            .IncludeBase<KycDocumentDto, KycDocument>();
    }
}

2. 统一管理映射配置(可选)

把所有映射配置从DTO内部移到单独的配置类中,更便于维护,避免每个DTO嵌套映射类:

public class KycMappingProfile : Profile
{
    public KycMappingProfile()
    {
        // 文档类映射
        CreateMap<KycDocument, KycDocumentDto>().ReverseMap();
        CreateMap<KycDocument, KycDocumentDetailDto>()
            .IncludeBase<KycDocument, KycDocumentDto>()
            .ReverseMap()
            .IncludeBase<KycDocumentDto, KycDocument>();

        // KYC主类映射
        CreateMap<KycInformation, KycInformationDto>().ReverseMap();
        CreateMap<KycInformation, KycInformationDetailDto>()
            .IncludeBase<KycInformation, KycInformationDto>()
            .ReverseMap()
            .IncludeBase<KycInformationDto, KycInformation>();
    }
}

之后删除各个DTO内部的Mapping类,启动时注册这个统一配置类即可。

3. 集合类型自动处理

只要正确配置了单个文档实体与DTO的映射,AutoMapper会自动处理集合类型的转换,不需要额外为Documents集合写重复规则。

方案优势

  • 用IncludeBase复用基础映射规则,避免重复编写相同属性的映射逻辑
  • 统一配置类让映射关系更清晰,便于后期维护
  • 集合映射依赖元素类型配置,减少冗余代码

内容的提问来源于stack exchange,提问作者nop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 19:52:08