Я использую EF Core 7 и C#. В модели у одного Employee
есть много Periods
и много Tickets
.
У меня есть следующие классы:
public class Employee
{
public string EmployeeId { get; set; }
public string FullName { get; set; }
public List<Period> Periods { get; set; }
public List<Ticket> Tickets { get; set; }
}
public class Period
{
public int PeriodId { get; set; }
public DateTime From { get; set; }
public DateTime To { get; set; }
public Employee Employee { get; set; }
public string EmployeeId { get; set; } //FK pointing to Employee
}
public class Ticket
{
public string TicketId { get; set; }
public DateTime CreationDate { get; set; }
public string EmployeeId { get; set; } //FK pointing to Employee
}
Как я могу написать запрос linq, который возвращает билеты, находящиеся в
диапазон периода сотрудников? Мне нужен результат в виде IQueryable<Ticket>
.
Вот запрос, который я пытался:
// I create a list of employees Id's
var employeeIds = new List<string> { "9854", "4587", "2587" };
IQueryable<Ticket> result =
from ticket in DbContext.Tickets
where employeeIds.Contains(ticket.EmployeeId) &&
// Here I need to set the condition for tickets
// that are inside the Period of each employee
// [Period.From , Period.To]
select ticket;
}
Действительно приятно видеть, что кто-то не забыл включить определение класса csharp в свой вопрос!
Это должно быть то, что вы хотите:
IQueryable<Ticket> result =
from ticket in DbContext.Tickets
where employeeIds.Contains(ticket.EmployeeId)
&& DbContext.Periods.Any(p => p.EmployeeId == ticket.EmployeeId
&& ticket.CreationDate >= p.From && ticket.CreationDate <= p.To)
select ticket;
Поэтому я проверяю, есть ли хотя бы один период для каждого сотрудника билета, который от/до находится в диапазоне CreationDate билета.
Если вас устраивает результат IEnumerable<Ticket>
вместо IQueryable<Ticket>
, вы также можете выполнить объединение идентификаторов сотрудников, заявок и периодов по идентификаторам сотрудников. а затем отфильтровать билеты по периодам «До/От».
//I create a list of employees Id's
var employeeIds = new List<string> {"9854", "4587", "2587"};
var tickets = new List<Ticket>
{
new Ticket {TicketId = "ticketId1", EmployeeId = "9854", CreationDate = new DateTime(2021, 9, 20)},
new Ticket {TicketId = "ticketId2", EmployeeId = "9854", CreationDate = new DateTime(2021, 10, 20)},
new Ticket {TicketId = "ticketId3", EmployeeId = "9855", CreationDate = new DateTime(2021, 9, 20)},
};
var periods = new List<Period>
{
new Period {PeriodId = 1, EmployeeId = "9854", From = new DateTime(2021, 8, 20), To = new DateTime(2021, 9, 21)},
new Period {PeriodId = 2, EmployeeId = "9854", From = new DateTime(2021, 10, 18), To = new DateTime(2021, 10, 21)},
};
var results = (from employeedId in employeeIds
join period in periods on employeedId equals period.EmployeeId into employeePeriods
join ticket in tickets on employeedId equals ticket.EmployeeId into employeeTickets
where employeeTickets.Count() > 0 && employeePeriods.Count() > 0
select new {employeePeriods, employeeTickets}).SelectMany(q =>
{
var employeeTickets = q.employeeTickets;
var employeePeriods = q.employeePeriods;
var ticketsWithinPeriod = employeeTickets.Where(t => employeePeriods.Any(p => p.From <= t.CreationDate && p.To >= t.CreationDate));
return ticketsWithinPeriod;
});
Результаты:
(1) Стоимость вашего билета
CreationDate
— это старые даты или дата/время? (2) Являются ли значения даты периодаTo
включенными в дату (00:00 последнего включенного дня) или исключительными датами (00:00 следующего дня)? -- Это существенно влияет на то, как вам нужно сравнивать даты с диапазонами дат.