Как использовать Automapper, чтобы сгладить список иерархий объектов? - PullRequest
0 голосов
/ 28 ноября 2018

Я хочу использовать automapper, чтобы сгладить список иерархий сущностей, возвращаемых из Entity Framework Core.

Вот мои сущности:

public class Employee {
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    public double? PayRateRegular { get; set; }
    public double? PayRateLoadedRegular { get; set; }
    public double? GMOutput { get; set; }
    public string EmployeeType { get; set; }

    //List of CommissionDetails where this employee is the consultant
    public IEnumerable<CommissionDetail> CommissionDetailConsultants { get; set; } = new List<CommissionDetail>();
}

public class Project {

    public int Id { get; set; }
    public string Description { get; set; }
    public double? BillRateRegular { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }

    public Customer Customer { get; set; }
    public int CustomerId { get; set; }

}

public class Customer {

    public int Id { get; set; }
    public string Name { get; set; }

}   

public class CommissionDetail {

    public string SaleType { get; set; }
    public double CommissionPercent { get; set; }
    public bool? IsReported { get; set; }
    public int? Level { get; set; }
    public string BasedOn { get; set; }

    public Project Project { get; set; }
    public int ProjectId { get; set; }

    public Employee SalesPerson { get; set; }
    public int SalesPersonEmployeeId { get; set; }

    public Employee Consultant { get; set; }
    public int ConsultantEmployeeId { get; set; }

}

Вот мой DTO:

public class ConsultantGridViewModel
{
    public string ConsultantName { get; set; }
    public string CustomerName { get; set; }
    public string SalesPersonName { get; set; }
    public string ProjectDescription { get; set; }
    public double? PayRate { get; set; }
    public double? LoadedRated { get; set; }
    public double? BillRate { get; set; }
    public double? GM { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public double CommissionPercent { get; set; }
    public int? CommissionLevel { get; set; }

}

Вот мой вызов EF:

        return await _dbContext.Employee
            .AsNoTracking()
            .Include(e => e.CommissionDetailConsultants)
                .ThenInclude(cd => cd.SalesPerson)
            .Include(e => e.CommissionDetailConsultants)
                .ThenInclude(cd => cd.Project)
                    .ThenInclude(p => p.Customer)
            .Where(e => e.EmployeeType == "Contractor")
            .ToListAsync();

В настоящее время я сглаживаю его с помощью SelectMany следующим образом:

var consultants = employees.SelectMany(e =>
    e.CommissionDetailConsultants,
    (emp, com) => new ConsultantGridViewModel {
        ConsultantName = emp.Name,
        PayRate = emp.PayRateRegular,
        LoadedRated = emp.PayRateLoadedRegular,
        GM = emp.GMOutput,
        BillRate = com.Project.BillRateRegular,
        ProjectDescription = com.Project.Description,
        ProjectStartDate = com.Project.StartDate,
        ProjectEndDate = com.Project.EndDate,
        CustomerName = com.Project.Customer.Name,
        SalesPersonName = com.SalesPerson.Name,
        CommissionPercent = com.CommissionPercent,
        CommissionLevel = com.Level
    });    

Я бы хотел использовать autopper вместо этого.Я использовал automapper для всех своих других отображений DTO, но я не могу понять, как использовать его для выравнивания вложенного объекта, как этот.

1 Ответ

0 голосов
/ 28 ноября 2018

Позвольте переписать то, что у вас есть на данный момент SelectMany + Select, используя свойство навигации Consultant:

var consultants = employees
    .SelectMany(e => e.CommissionDetailConsultants)
    .Select(com => new ConsultantGridViewModel
    {
        ConsultantName = com.Consultant.Name,
        PayRate = com.Consultant.PayRateRegular,
        LoadedRated = com.Consultant.PayRateLoadedRegular,
        GM = com.Consultant.GMOutput,
        BillRate = com.Project.BillRateRegular,
        ProjectDescription = com.Project.Description,
        ProjectStartDate = com.Project.StartDate,
        ProjectEndDate = com.Project.EndDate,
        CustomerName = com.Project.Customer.Name,
        SalesPersonName = com.SalesPerson.Name,
        CommissionPercent = com.CommissionPercent,
        CommissionLevel = com.Level
    });

Теперь видно, что CommissionDetail содержит все необходимые данные,поэтому, хотя вы не можете избежать SelectMany, вы можете заменить Select, создав отображение от CommissionDetail до ConsultantGridViewModel и использовать что-то вроде этого:

var consultants = Mapper.Map<List<ConsultantGridViewModel>>(
    employees.SelectMany(e => e.CommissionDetailConsultants));

или даже лучше, проектнепосредственно к DTO:

var consultants = await _dbContext.Employee
    .Where(e => e.EmployeeType == "Contractor")
    .SelectMany(e => e.CommissionDetailConsultants)
    .ProjectTo<ConsultantGridViewModel>()
    .ToListAsync();

Теперь отображение.

AutoMapper автоматически сопоставит элементы, такие как CommisionPercent.Кроме того, функция Сглаживание автоматически обрабатывает сопоставления, такие как Project.EndDate -> ProjectEndDate, Consultant.Name -> ConsultantName и т. Д.

Так что, как обычно, в AutoMapper вы должны указать вручнуюотображение свойств, которые не попадают в предыдущие категории.Минимальная конфигурация в этом случае будет выглядеть примерно так:

Mapper.Initialize(cfg =>
{
    cfg.CreateMap<CommissionDetail, ConsultantGridViewModel>()
        .ForMember(dst => dst.PayRate, opt => opt.MapFrom(src => src.Consultant.PayRateRegular))
        .ForMember(dst => dst.LoadedRated, opt => opt.MapFrom(src => src.Consultant.PayRateLoadedRegular))
        .ForMember(dst => dst.GM, opt => opt.MapFrom(src => src.Consultant.GMOutput))
        .ForMember(dst => dst.BillRate, opt => opt.MapFrom(src => src.Project.BillRateRegular))
        .ForMember(dst => dst.CustomerName, opt => opt.MapFrom(src => src.Project.Customer.Name))
        .ForMember(dst => dst.CommissionLevel, opt => opt.MapFrom(src => src.Level));
});

PS Вы даже можете избежать SelectMany, основав свои запросы непосредственно на CommissionDetail сущности, например

var consultants = await _dbContext.Set<CommissionDetail>()
    .Where(c => c.Consultant.EmployeeType == "Contractor")
    .ProjectTo<ConsultantGridViewModel>()
    .ToListAsync();

Обратите внимание, что при прямом проецировании нет необходимости в AsNoTracking или Include / ThenInclude.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...