寻找有关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)
})
要接收数据,我正在使用存储库模式。然后使用AutoMapper将所有数据映射到ViewModel。这是我的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; }
}
现在,我尝试获取有关Company(AbpTenants)的信息以及有关Edition(一对多关系)和TicketLinkedUsers列表(多对多关系)的信息以及TicketLinkType信息。架构:
我可以使用其他联接来接收所有必需的数据,但是我不知道如何正确绑定数据并将其映射到GetTicketForView。这里是一个带有嵌套嵌套的Edition版本的LinkedUsers和Tenant列表。现在,我正在为每张票单独进行请求以进行多对多工作:
// 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中映射复杂的东西?
预先感谢
答案 0 :(得分:0)
按照提示,我重写了所有内容
查询:
var query = filteredTickets // IQueryable<Ticket>
.Include(ten => ten.Tenant)
.ThenInclude(ed => ed.Edition)
.Include(p => p.Product)
.Include(pv => pv.ProductVersion)
.Include(tt => tt.TicketType)
.Include(tp => tp.TicketPriority)
.Include(ts => ts.TicketState)
.Include(lu => lu.LinkedUsers)
.ThenInclude(tlt => tlt.TicketLinkType)
.Include(lu => lu.LinkedUsers)
.ThenInclude(u => u.User)
.ProjectTo<GetTicketForView>();
映射:
configuration.CreateMap<Ticket, TicketDto>();
configuration.CreateMap<Tenant, TenantShortInfoDto>();
configuration.CreateMap<TicketState, TicketStateTableDto>();
configuration.CreateMap<TicketLinkedUser, TicketLinkedUserDto>();
configuration.CreateMap<Ticket, GetTicketForView>()
.ForMember(dest => dest.Ticket, conf => conf.MapFrom(src => src)
);
不确定将来是否要切换到nhibernate,是否会失去灵活性,但是它的工作原理比以前好得多。