Нужна помощь с Ef Core и Linq.
Допустим, я делаю большой запрос на получение всех билетов поддержки с информацией о продукте, компании и так далее. Это довольно просто, просто присоединяясь к вещам:
select *
from Tickets T
left join Products P on T.ProductId = P.Id
left join ProductVersions PV on T.ProductVersionId = PV.Id
left join TicketTypes TT on T.TicketTypeId = TT.Id
left join TicketPriorities TP on T.TicketPriorityId = TP.Id
left join TicketStates TS on T.TicketStateId = TS.Id
left join AbpTenants A on T.TenantId = A.Id
left join AbpEditions E on A.EditionId = E.Id
left join TicketLinkedUsers TLU on TLU.TicketId = T.Id
left join TicketLinkTypes TLT on TLT.Id = TLU.TicketLinkTypeId
Однако у меня есть проблемы с последними 4 соединениями.
В проекте я использую Ef Core. Вот как я это сделал (частично):
var query = (from o in filteredTickets
join o1 in _productRepository.GetAll() on o.ProductId equals o1.Id into j1
from s1 in j1.DefaultIfEmpty()
join o2 in _productVersionRepository.GetAll() on o.ProductVersionId equals o2.Id into j2
from s2 in j2.DefaultIfEmpty()
join o3 in _ticketTypeRepository.GetAll() on o.TicketTypeId equals o3.Id into j3
from s3 in j3.DefaultIfEmpty()
join o4 in _ticketPriorityRepository.GetAll() on o.TicketPriorityId equals o4.Id into j4
from s4 in j4.DefaultIfEmpty()
join o5 in _ticketStateRepository.GetAll() on o.TicketStateId equals o5.Id into j5
from s5 in j5.DefaultIfEmpty()
join o6 in _tenantManager.Tenants on o.TenantId equals o6.Id into j6
from s6 in j6.DefaultIfEmpty()
// join o7 in _editionaRepository.GetAll() on s6.EditionId equals o7.Id into j7
// from s7 in j7.DefaultIfEmpty()
// join o8 in _ticketLinkedUsersRepository.GetAll() on o.Id equals o8.TicketId into j8
// from s8 in j8.DefaultIfEmpty()
// join o9 in _ticketLinkTypesRepository.GetAll() on s9.TicketLinkTypeId equals o9.Id into j9
// from s9 in j9.DefaultIfEmpty()
select new GetTicketForView() { Ticket = ObjectMapper.Map<TicketDto>(o)
, ProductName = s1 == null ? "" : s1.Name.ToString()
, ProductVersionName = s2 == null ? "" : s2.Name.ToString()
, TicketTypeName = s3 == null ? "" : s3.Name.ToString()
, TicketPriorityName = s4 == null ? "" : s4.Name.ToString()
, TicketState = ObjectMapper.Map<TicketStateTableDto>(s5)
, Tenant = ObjectMapper.Map<TenantShortInfoDto>(s6)
})
Для получения данных я использую шаблон репозитория. И тогда все данные сопоставляются с ViewModel с помощью AutoMapper. Вот как выглядит моя ViewModel:
public class GetTicketForView
{
public TicketDto Ticket { get; set; }
public TenantShortInfoDto Tenant { get; set; }
public string ProductName { get; set;}
public string ProductVersionName { get; set;}
public TicketStateTableDto TicketState { get; set; }
public string TicketTypeName { get; set;}
public string TicketPriorityName { get; set;}
public List<TicketLinkedUserDto> LinkedUsers { get; set; }
}
Теперь я пытаюсь получить информацию о компании (AbpTenants) с информацией о Edition (отношение один ко многим) и список TicketLinkedUsers (отношение многие ко многим) с информацией TicketLinkType. Схема:
![enter image description here](https://i.stack.imgur.com/opxuk.png)
Я могу получать все необходимые данные с помощью дополнительных объединений, однако я не знаю, как правильно связывать и отображать данные в GetTicketForView. Список LinkedUsers и Tenant с вложенным отображением Edition является проблемой здесь. Прямо сейчас я делаю отдельный запрос для каждого билета, чтобы заставить многих работать:
// execute to get tickets
tickets = await query
.OrderBy(input.Sorting ?? "ticket.id asc")
.PageBy(input)
.ToListAsync();
// then for each ticket get related users:
foreach (var ticket in tickets)
{
var linkedUsers = _ticketLinkedUsersRepository
.GetAllIncluding(lu => lu.TicketLinkType, lu => lu.User)
.OrderBy(a => a.TicketLinkType.Ordinal)
.Where(p => p.TicketId == ticket.Ticket.Id).ToList();
ticket.LinkedUsers = ObjectMapper.Map<List<TicketLinkedUserDto>>(linkedUsers);
}
Это отнимает много времени, потому что я могу получить все данные за один запрос, используя o8 и 09, но я делаю дополнительный запрос для каждого билета. Не хватает опыта, чтобы все исправить.
Итак, вопрос в том, как я могу реализовать первый запрос с помощью linq и сопоставить его с ViewModel. Должен ли я использовать дополнительный запрос? Или лучше использовать Ef Core Api для сложного запроса? Или невозможно отобразить сложные вещи внутри linq?
Заранее спасибо