【问题标题】:How to properly define AutoMapper config for complex class?如何正确定义复杂类的 AutoMapper 配置?
【发布时间】:2018-02-26 23:20:41
【问题描述】:

我正在使用实体框架,并准备重做一个当前使用 EF->BDO->DTO->client 的项目,并在此过程中为每个类进行手动转换。

我遇到了 AutoMapper,并认为这将是一个整体上更好的解决方案。我在映射 CustomerEF -> CustomerDto、OfficeEF -> OfficeDto 等时没有遇到任何问题,但我现在正在研究一个更复杂的类,并且努力让一切都到位。

我觉得我很接近,并且必须反过来发生一些事情,但我无法确定我错过了什么。

    public class CaseDto
{
    public int CaseId { get; set; }
    public string CaseReason { get; set; }
    public CustomersDto _customer { get; set; }
    public OfficeDto _office { get; set; }
    public CaseNotesDto[] _caseNotes { get; set; }
}

public class CustomersDto
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }
}

public class OfficeDto
{
    public int OfficeId { get; set; }
    public string OfficeName { get; set; }
}

public class CaseNotesDto
{
    public int CaseNotesId { get; set; }
    public int CaseId { get; set; }
    public string CaseNote { get; set; }
}

// EF objects

public class CaseEF
{
    public int CaseId { get; set; }
    public string CaseReason { get; set; }
    public int CustomerId { get; set; }
    public int OfficeId { get; set; }
}

public class CustomerEF
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }
}

public class OfficeEF
{
    public int OfficeId { get; set; }
    public string OfficeName { get; set; }
}

public class CaseNotesEF
{
    public int CaseNotesId { get; set; }
    public int CaseId { get; set; }
    public string CaseNote { get; set; }
}

// execution classes

public class CaseFramework
{
    // set 'ef' variables
    private readonly OfficeEF _officeEf = new OfficeEF { OfficeId = 1, OfficeName = "Washington" };
    private readonly CustomerEF _customerEf = new CustomerEF { CustomerId = 1, CustomerName = "Blips and Chitz" };

    private readonly CaseNotesEF[] _caseNotesEf = 
    {
        new CaseNotesEF {CaseNotesId = 1, CaseNote = "Case 1", CaseId = 1000},
        new CaseNotesEF {CaseNotesId = 2, CaseNote = "Case 2", CaseId = 1000}
    };

    private readonly CaseEF _case =
        new CaseEF { CaseId = 1000, CaseReason = "Roy is back!", CustomerId = 1, OfficeId = 1 };

    public CaseDto GetCase(int caseId)
    {
        Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<OfficeEF, OfficeDto>();
            cfg.CreateMap<CustomerEF, CustomersDto>();
            cfg.CreateMap<CaseNotesEF, CaseNotesDto>();
            cfg.CreateMap<CaseEF, CaseDto>()
                .ForMember(dest => dest._customer, opt => opt.MapFrom(src => src.CustomerId))
                .ForMember(dest => dest._office, opt => opt.MapFrom(src => src.OfficeId))
                .ForMember(dest => dest._caseNotes,
                    opt => opt.MapFrom(src => _caseNotesEf.Where(x => x.CaseId == caseId)));
        });

        Mapper.AssertConfigurationIsValid();

        var source = new CaseEF { CaseId = caseId };
        var destination = Mapper.Map<CaseEF, CaseDto>(source);


        return destination;
    }
}

为了运行这个我正在做的事情:

var b = new CaseFramework();
var result = b.GetCase(1000);

结果是填充 CaseId(手动设置)和 CaseNotesDto,但仅此而已。

在 Mapper.Initialize 部分中拥有前 3 个 cfg.CreateMap 项无论它们是否存在都没有区别。

提前感谢您的任何指导。

【问题讨论】:

  • 一个更好的整体解决方案是使用适合您所有层的 T4 生成的 POCO 类,而不是每个层。 Canonical schema/model 消除了所有繁琐且耗时的数据转换;消除了数据保真度丢失的风险并大大减少了维护
  • 基本上,你不能从一个 id 映射到一个类。您的案例实体 (CaseEF) 下方应有 navigation properties (classes) 用于客户、办公室和案例说明。带有 EF 的 automapper 的美妙之处在于您可以一步获取它们并一步映射它们(不需要.ForMember(),除非您正在做一些不正常的事情)。
  • 完成后,它可能看起来像var caseDTO = context.Cases.Include(c =&gt; c.Customer).Include(c =&gt; c.Office).Include(c =&gt; c.Notes).Project().To&lt;CaseDTO&gt;().ToList();

标签: c# entity-framework-6 automapper


【解决方案1】:

感谢您的回复。

@MickyD,我对 POCO 的评论有点困惑,因为 EF 已经生成了一个 tt,而规范模式/模型看起来我必须进行更多研究。

@Steve 我从我的 EF 数据库中检查了我的导航属性,我们需要在使 Include 方法工作之前对关系进行一些修复,但我认为这最终将成为解决方案。与此同时,我能够通过以下方式实现最初的目标:

            Mapper.AssertConfigurationIsValid();

            var destination = Mapper.Map<CaseDto>(_case);
            destination.Customers = Mapper.Map<CustomerEF, CustomersDto>(_customerEf);
            destination.Office = Mapper.Map<OfficeEF, OfficeDto>(_officeEf);

            return destination;

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    相关资源
    最近更新 更多