feat(api): оптимизация запросов на получение списка шаблонов, обновлен response

This commit is contained in:
Mikhail Trubnikov
2026-01-29 16:53:00 +10:00
parent 3b7213182c
commit 5222d763f9
4 changed files with 216 additions and 89 deletions

View File

@@ -30,6 +30,11 @@ namespace PARR.API.Contracts.V1.Requests.Queries
/// Статус синхронизации шаблонов и расписаний /// Статус синхронизации шаблонов и расписаний
/// </summary> /// </summary>
public TemplateQuerySyncStatusEnum? SyncStatus { get; set; } public TemplateQuerySyncStatusEnum? SyncStatus { get; set; }
/// <summary>
/// Применять шорткоды
/// </summary>
public bool? ApplyShortcode { get; set; }
} }
/// <summary> /// <summary>

View File

@@ -1,6 +1,6 @@
namespace PARR.API.Contracts.V1.Responses namespace PARR.API.Contracts.V1.Responses
{ {
public class TemplateResponse public class TemplateBaseResponse
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
@@ -10,6 +10,46 @@
public bool IsActiveSchedule { get; set; } public bool IsActiveSchedule { get; set; }
public string? ScheduleEsppId { get; set; }
public DateTimeOffset? LastRun { get; set; }
public DateTimeOffset NextRun { get; set; }
/// <summary>
/// Рабочая группа (формируется из шорткода)
/// </summary>
public string? WorkGroup { get; set; }
/// <summary>
/// ЗО, формируется из шорткода
/// </summary>
public string? ResponseArea { get; set; }
public UnitWithAttributesResponse? Unit { get; set; }
public TemplateStatusTypeResponse? StatusType { get; set; }
public TemplateAgentResponse? Agent { get; set; }
public List<RobotConfigurationResponse>? SyncStatus { get; set; }
public int OrderCount { get; set; }
public bool IsAutoDistributionEnabled { get; set; }
}
public class TemplateListResponse : TemplateBaseResponse
{
}
public class TemplateResponse : TemplateBaseResponse
{
public required string Category { get; set; } public required string Category { get; set; }
public required string Initiator { get; set; } public required string Initiator { get; set; }
@@ -24,29 +64,6 @@
public required string TemplateDuration { get; set; } public required string TemplateDuration { get; set; }
/// <summary>
/// Рабочая группа (формируется из шорткода)
/// </summary>
public required string WorkGroup { get; set; }
/// <summary>
/// ЗО, формируется из шорткода
/// </summary>
public required string ResponseArea { get; set; }
public TemplateAgentResponse? Agent { get; set; }
public DateTimeOffset? LastRun { get; set; }
public DateTimeOffset NextRun { get; set; }
public bool IsAutoDistributionEnabled { get; set; }
public string? ScheduleEsppId { get; set; }
//public UnitResponse? Unit { get; set; }
public UnitWithAttributesResponse? Unit { get; set; }
public JobResponse? Job { get; set; } public JobResponse? Job { get; set; }
public ProcessResponse? Process { get; set; } public ProcessResponse? Process { get; set; }
@@ -55,8 +72,6 @@
public TnkResponse? Tnk { get; set; } public TnkResponse? Tnk { get; set; }
public List<RobotConfigurationResponse>? SyncStatus { get; set; }
/// <summary> /// <summary>
/// Расписание /// Расписание
/// </summary> /// </summary>
@@ -72,10 +87,6 @@
/// </summary> /// </summary>
public ScheduleExcludeTypeCalendarResponse? ScheduleExcludeTypeCalendar { get; set; } public ScheduleExcludeTypeCalendarResponse? ScheduleExcludeTypeCalendar { get; set; }
public int OrderCount { get; set; }
public TemplateStatusTypeResponse? StatusType { get; set; }
public JobGroupDistributionConfigResponse? DistributionConfig { get; set; } public JobGroupDistributionConfigResponse? DistributionConfig { get; set; }
} }
} }

View File

@@ -18,6 +18,7 @@ using PARR.DAL.DomainModels;
using PARR.DAL.DomainServices.Shortcodes; using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using System.Diagnostics;
namespace PARR.API.Controllers.V1 namespace PARR.API.Controllers.V1
{ {
@@ -33,6 +34,7 @@ namespace PARR.API.Controllers.V1
private readonly IClientService clientService; private readonly IClientService clientService;
private readonly ILogger<TemplateController> logger; private readonly ILogger<TemplateController> logger;
private readonly IShortcodesService shortcodesService; private readonly IShortcodesService shortcodesService;
private readonly IOrderService orderService;
public TemplateController( public TemplateController(
IMapper mapper, IMapper mapper,
@@ -40,7 +42,8 @@ namespace PARR.API.Controllers.V1
IRobotConfigurationService robotConfigurationService, IRobotConfigurationService robotConfigurationService,
IClientService clientService, IClientService clientService,
ILogger<TemplateController> logger, ILogger<TemplateController> logger,
IShortcodesService shortcodesService IShortcodesService shortcodesService,
IOrderService orderService
) )
{ {
this.mapper = mapper; this.mapper = mapper;
@@ -49,6 +52,7 @@ namespace PARR.API.Controllers.V1
this.clientService = clientService; this.clientService = clientService;
this.logger = logger; this.logger = logger;
this.shortcodesService = shortcodesService; this.shortcodesService = shortcodesService;
this.orderService = orderService;
} }
@@ -62,18 +66,31 @@ namespace PARR.API.Controllers.V1
{ {
var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery); var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
IQueryable<Template> query = templateService.GetWithIncludes().AsNoTracking() //IQueryable<Template> query = templateService.GetWithIncludes().AsNoTracking()
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field) // .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value) // .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot) // .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus) // .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus) // .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
.Include(t => t.Orders) // .Include(t => t.Orders)
.Include(t => t.StatusType) // .Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType) // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar) // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
.OrderBy(t => t.Name) // .OrderBy(t => t.Name)
.AsSplitQuery(); // .AsSplitQuery();
//var sw = Stopwatch.StartNew();
IQueryable<Template> query = templateService.Get()
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
.Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
.OrderBy(t => t.Name)
.AsNoTracking();
if (!string.IsNullOrEmpty(filter.Mask)) if (!string.IsNullOrEmpty(filter.Mask))
@@ -106,16 +123,42 @@ namespace PARR.API.Controllers.V1
var templates = await templateService.GetPage(query, paginationFilter).ToListAsync(); var templates = await templateService.GetPage(query, paginationFilter).ToListAsync();
//logger.LogDebug("Загрузка шаблонов из БД: {ElapsedMs} мс", sw.ElapsedMilliseconds);
if (!templates.Any()) if (!templates.Any())
return NoContent(); return NoContent();
var templateResponse = mapper.Map<List<TemplateResponse>>(templates); var templateResponse = mapper.Map<List<TemplateListResponse>>(templates);
foreach (var responseItem in templateResponse)
{
await ApplyTemplateShortcodesAsync(responseItem, templates.First(t => t.Id == responseItem.Id));
}
var paginationResponse = new PagedResponse<TemplateResponse>(templateResponse, true).GetPaginatedProps(paginationFilter, query); // словари для быстрого поиска
var templatesDict = templates.ToDictionary(t => t.Id);
var templateResponseDict = templateResponse.ToDictionary(t => t.Id);
#region Заполняем шорткоды
if (filter.ApplyShortcode == true)
{
//sw.Restart();
foreach (var responseItem in templateResponse)
{
//await ApplyTemplateShortcodesAsync(responseItem, templates.First(t => t.Id == responseItem.Id));
await ApplyTemplateShortcodesAsync(responseItem, templatesDict[responseItem.Id]);
}
//logger.LogDebug("Получение шорткодов: {ElapsedMs} мс", sw.ElapsedMilliseconds);
//sw.Stop();
}
#endregion
#region заполнение OrdersCount
var templatesWithOrdersCount = await GetOrdersCountAsync(templates.Select(t => t.Id).ToList());
foreach (var (templateId, orderCount) in templatesWithOrdersCount)
{
if (templateResponseDict.TryGetValue(templateId, out var response))
response.OrderCount = orderCount;
}
#endregion
var paginationResponse = new PagedResponse<TemplateListResponse>(templateResponse, true).GetPaginatedProps(paginationFilter, query);
return Ok(paginationResponse); return Ok(paginationResponse);
} }
@@ -129,12 +172,10 @@ namespace PARR.API.Controllers.V1
public async Task<IActionResult> GetById([FromRoute] Guid id) public async Task<IActionResult> GetById([FromRoute] Guid id)
{ {
var template = await templateService.GetWithIncludes().AsNoTracking() var template = await templateService.GetWithIncludes().AsNoTracking()
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot) .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus) .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus) .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
.Include(t => t.Orders) //.Include(t => t.Orders)
.Include(t => t.StatusType) .Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType) .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar) .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
@@ -147,6 +188,9 @@ namespace PARR.API.Controllers.V1
var response = mapper.Map<TemplateResponse>(template); var response = mapper.Map<TemplateResponse>(template);
await ApplyTemplateShortcodesAsync(response, template); await ApplyTemplateShortcodesAsync(response, template);
var ordersCountResult = await GetOrdersCountAsync(new List<Guid> { response.Id });
response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0;
return Ok(new Response<TemplateResponse>(response, true)); return Ok(new Response<TemplateResponse>(response, true));
} }
@@ -161,19 +205,24 @@ namespace PARR.API.Controllers.V1
{ {
//TODO:!!! Возможно тут не надо сразу менять, а отправить запрос в TemplateActivator и пусть он сам занимается своей работой!!! //TODO:!!! Возможно тут не надо сразу менять, а отправить запрос в TemplateActivator и пусть он сам занимается своей работой!!!
#region old
//var template = await templateService.GetWithIncludes()
// //.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
// //.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
// .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
// .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
// .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
// .Include(t => t.Orders)
// .Include(t => t.StatusType)
// .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
// .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
// .AsSplitQuery()
// .FirstOrDefaultAsync(t => t.Id == id);
#endregion
var template = await templateService.GetWithIncludes() var template = await templateService.Get()
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field) .Include(t => t.RobotConfigurations)
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value) .FirstOrDefaultAsync(t => t.Id == id);
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
.Include(t => t.Orders)
.Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
.AsSplitQuery()
.FirstOrDefaultAsync(t => t.Id == id);
if (template == null) if (template == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не найден шаблона с id: {id}" } })); return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не найден шаблона с id: {id}" } }));
@@ -197,31 +246,83 @@ namespace PARR.API.Controllers.V1
if (!await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Изменён статус шаблона/расписания", InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api })) if (!await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Изменён статус шаблона/расписания", InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api }))
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении шаблона." } })); return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении шаблона." } }));
var templateToResponse = await templateService.GetWithIncludes().AsNoTracking() #region old
.Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Field) //var templateToResponse = await templateService.GetWithIncludes().AsNoTracking()
.Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Value) // //.Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Field)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot) // //.Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Value)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus) // .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus) // .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.Orders) // .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
.Include(t => t.StatusType) // .Include(t => t.Orders)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType) // .Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar) // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
.AsSplitQuery() // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
.FirstAsync(t => t.Id == id); // .AsSplitQuery()
// .FirstAsync(t => t.Id == id);
//var response = mapper.Map<TemplateResponse>(templateToResponse);
//await ApplyTemplateShortcodesAsync(response, templateToResponse);
//return Ok(new Response<TemplateResponse>(response, true));
#endregion
var templateToResponse = await templateService.Get()
.AsNoTracking()
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
.Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
.FirstAsync(t => t.Id == id);
var response = mapper.Map<TemplateListResponse>(templateToResponse);
var response = mapper.Map<TemplateResponse>(templateToResponse);
await ApplyTemplateShortcodesAsync(response, templateToResponse); await ApplyTemplateShortcodesAsync(response, templateToResponse);
return Ok(new Response<TemplateResponse>(response, true)); var ordersCountResult = await GetOrdersCountAsync(new List<Guid> { response.Id });
response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0;
return Ok(new Response<TemplateListResponse>(response, true));
} }
private async Task ApplyTemplateShortcodesAsync(TemplateResponse response, Template template) /// <summary>
/// Применить шорткоды
/// </summary>
/// <param name="response"></param>
/// <param name="template"></param>
/// <returns></returns>
private async Task ApplyTemplateShortcodesAsync(TemplateBaseResponse response, Template template)
{ {
response.WorkGroup = await shortcodesService.ApplyShortcodesAsync(template.Job.WorkGroupMask, template); response.WorkGroup = await shortcodesService.ApplyShortcodesAsync(template.Job.WorkGroupMask, template);
response.ResponseArea = await shortcodesService.ApplyShortcodesAsync(template.Job.ResponseAreaMask, template); response.ResponseArea = await shortcodesService.ApplyShortcodesAsync(template.Job.ResponseAreaMask, template);
} }
/// <summary>
/// Получить кол-во нарядов для шаблонов
/// </summary>
/// <param name="templateIdList"></param>
/// <returns></returns>
private async Task<Dictionary<Guid, int>> GetOrdersCountAsync(List<Guid> templateIdList)
{
if (!templateIdList.Any())
return new Dictionary<Guid, int>();
var templateWithOrders = await orderService.Get()
.Where(t => t.TemplateId.HasValue && templateIdList.Contains(t.TemplateId.Value))
.GroupBy(t => t.TemplateId)
.Select(t => new { TemplateId = t.Key, OrderCount = t.Count() })
.AsNoTracking()
.ToListAsync();
if (templateWithOrders == null)
return new Dictionary<Guid, int>();
return templateWithOrders.ToDictionary(t => t.TemplateId!.Value, t => t.OrderCount);
}
} }
} }

View File

@@ -18,9 +18,21 @@ namespace PARR.API.MappingProfiles
#region Template #region Template
// --- Template --- // --- Template ---
CreateMap<Template, TemplateBaseResponse>()
.Include<Template, TemplateResponse>()
.Include<Template, TemplateListResponse>()
.ForMember(d => d.Unit, o => o.MapFrom(s => s.Unit))
.ForMember(d => d.StatusType, o => o.MapFrom(s => s.StatusType))
.ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!))
.ForMember(d => d.SyncStatus, o => o.MapFrom(s => s.RobotConfigurations.OrderBy(t => t.RobotCode)))
.ForMember(d => d.OrderCount, o => o.MapFrom(s => s.Orders.Count()))
.ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled));
CreateMap<Template, TemplateListResponse>();
CreateMap<Template, TemplateResponse>() CreateMap<Template, TemplateResponse>()
.ForMember(d => d.Job, o => o.MapFrom(s => s.Job)) .ForMember(d => d.Job, o => o.MapFrom(s => s.Job))
.ForMember(d => d.Unit, o => o.MapFrom(s => s.Unit)) //.ForMember(d => d.Unit, o => o.MapFrom(s => s.Unit))
.ForMember(d => d.Process, o => o.MapFrom(s => s.Job!.Tnk!.Subprocess!.Process)) .ForMember(d => d.Process, o => o.MapFrom(s => s.Job!.Tnk!.Subprocess!.Process))
.ForMember(d => d.Subprocess, o => o.MapFrom(s => s.Job!.Tnk!.Subprocess)) .ForMember(d => d.Subprocess, o => o.MapFrom(s => s.Job!.Tnk!.Subprocess))
.ForMember(d => d.Tnk, o => o.MapFrom(s => s.Job!.Tnk)) .ForMember(d => d.Tnk, o => o.MapFrom(s => s.Job!.Tnk))
@@ -31,16 +43,14 @@ namespace PARR.API.MappingProfiles
.ForMember(d => d.Initiator, o => o.MapFrom<TemplateInitiatorResolver>()) .ForMember(d => d.Initiator, o => o.MapFrom<TemplateInitiatorResolver>())
.ForMember(d => d.ClosingCode, o => o.MapFrom<TemplateClosingCodeResolver>()) .ForMember(d => d.ClosingCode, o => o.MapFrom<TemplateClosingCodeResolver>())
.ForMember(d => d.Category, o => o.MapFrom<TemplateCategoryResolver>()) .ForMember(d => d.Category, o => o.MapFrom<TemplateCategoryResolver>())
.ForMember(d => d.SyncStatus, o => o.MapFrom(s => s.RobotConfigurations.OrderBy(t => t.RobotCode))) //.ForMember(d => d.SyncStatus, o => o.MapFrom(s => s.RobotConfigurations.OrderBy(t => t.RobotCode)))
.ForMember(d => d.Schedule, o => o.MapFrom<TemplateScheduleResolver>()) .ForMember(d => d.Schedule, o => o.MapFrom<TemplateScheduleResolver>())
.ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!)) //.ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!))
//.ForMember(d => d.NextRun, o => o.MapFrom(s => s.ApplicationsInWork!.NextRun)) //.ForMember(d => d.NextRun, o => o.MapFrom(s => s.NextRun))
//.ForMember(d => d.LastRun, o => o.MapFrom(s => s.ApplicationsInWork!.LastRun)) //.ForMember(d => d.LastRun, o => o.MapFrom(s => s.LastRun))
.ForMember(d => d.NextRun, o => o.MapFrom(s => s.NextRun)) //.ForMember(d => d.OrderCount, o => o.MapFrom(s => s.Orders.Count()))
.ForMember(d => d.LastRun, o => o.MapFrom(s => s.LastRun)) //.ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled))
.ForMember(d => d.OrderCount, o => o.MapFrom(s => s.Orders.Count())) //.ForMember(d => d.StatusType, o => o.MapFrom(s => s.StatusType))
.ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled))
.ForMember(d => d.StatusType, o => o.MapFrom(s => s.StatusType))
.ForMember(d => d.ScheduleExcludeType, o => o.MapFrom(s => s.Job!.Group!.ScheduleExcludeType)) .ForMember(d => d.ScheduleExcludeType, o => o.MapFrom(s => s.Job!.Group!.ScheduleExcludeType))
.ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.Job!.Group!.ScheduleExcludeTypeCalendar)) .ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.Job!.Group!.ScheduleExcludeTypeCalendar))
.ForMember(d => d.DistributionConfig, o => o.MapFrom(s => s.Job.Group.DistributionConfig)) .ForMember(d => d.DistributionConfig, o => o.MapFrom(s => s.Job.Group.DistributionConfig))