我有一个前开发人员编写的以下LINQ查询,它应该在它应该工作时不起作用。
public bool IsAvailable(Appointment appointment)
{
var appointments = _appointmentRepository.Get;
var shifts = _scheduleRepository.Get;
var city = _customerRepository.Find(appointment.CustomerId).City ?? appointment.Customer.City;
const int durationHour = 1;
DateTime scheduledEndDate = appointment.ScheduledTime.Add(new TimeSpan(durationHour, 0, 0));
var inWorkingHours = shifts
.Where(x =>
//Check if any available working hours
x.Employee.City == city &&
x.ShiftStart <= appointment.ScheduledTime &&
x.ShiftEnd >= scheduledEndDate &&
//check if not booked yet
!appointments
.Where(a =>
(appointment.Id == 0 || a.Id != appointment.Id) &&
a.Employee.Id == x.Employee.Id &&
(
(a.ScheduledTime <= appointment.ScheduledTime &&
appointment.ScheduledTime <= EntityFunctions.AddHours(a.ScheduledTime, durationHour)) ||
(a.ScheduledTime <= scheduledEndDate &&
scheduledEndDate <= EntityFunctions.AddHours(a.ScheduledTime, durationHour))
))
.Select(a => a.Employee.Id)
.Contains(x.Employee.Id)
);
if (inWorkingHours.Any())
{
var assignedEmployee = inWorkingHours.FirstOrDefault().Employee;
appointment.EmployeeId = assignedEmployee.Id;
appointment.Employee = assignedEmployee;
return true;
}
return false;
}
类
public class Appointment
{
[Key]
public int Id { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public DateTime ScheduledTime { get; set; }
public int? EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Province { get; set; }
public string PostalCode { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public virtual string Fullname { get { return FirstName + " " + LastName; } }
public Customer(){ }
}
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Province { get; set; }
public string PostalCode { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public virtual string Fullname { get { return FirstName + " " + LastName; } }
public Employee() { }
}
public class Shift
{
[Key]
public int Id { get; set; }
public DateTime ShiftStart { get; set; }
public DateTime ShiftEnd { get; set; }
public int EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
}
该查询假设处理以下场景
如果客户与员工不在同一个城市,我们将约会分配为“未分配”,因为预定时间在员工班次开始/结束时间之内
如果客户与员工在同一个城市,我们会将约会分配给其中一个员工(firstOrdefault)并占用该时间段。
约会不能重叠(已分配的人)。未分配不能相互重叠。
此查询用于工作(我被告知)。但现在它没有,我已经尝试重构它和各种其他路径没有运气。我现在在第二周,只是不知道查询中的问题在哪里或如何编写它。
如果我需要进一步发布,请告诉我。我已经验证了约会,轮班,城市都填充了有效数据,因此问题似乎没有空或缺少数据。
答案 0 :(得分:2)
首先,它不是100%明确你的意思是什么“这个查询用来工作(我被告知)。但现在它没有”。你能否提供一些案例,说明它“不起作用”?
从我的观点来看,查询看起来几乎是正确的,但我猜有些奇怪的事情。让我们看看这段代码:
!appointments
.Where(a =>
(appointment.Id == 0 || a.Id != appointment.Id) &&
a.Employee.Id == x.Employee.Id &&
(
(a.ScheduledTime <= appointment.ScheduledTime &&
appointment.ScheduledTime <= EntityFunctions.AddHours(a.ScheduledTime, durationHour)) ||
(a.ScheduledTime <= scheduledEndDate &&
scheduledEndDate <= EntityFunctions.AddHours(a.ScheduledTime, durationHour))
))
.Select(a => a.Employee.Id)
.Contains(x.Employee.Id)
在WHERE条件中,除了您a.Employee.Id == x.Employee.Id
过滤的所有内容之外。这意味着WHERE子句之后的集合将仅包含单个员工的约会。所以我想我们可以将这部分重写为:
!appointments.Any(a =>
(appointment.Id == 0 || a.Id != appointment.Id) &&
a.Employee.Id == x.Employee.Id &&
(
(a.ScheduledTime <= appointment.ScheduledTime &&
appointment.ScheduledTime <= EntityFunctions.AddHours(a.ScheduledTime, durationHour)) ||
(a.ScheduledTime <= scheduledEndDate &&
scheduledEndDate <= EntityFunctions.AddHours(a.ScheduledTime, durationHour))
))
可能是另一个问题:比较开始/结束日期。在上面的代码中,您将检查以下内容:
.........[----------------]...........
^^^^^^
||||||
start date and end date
not in this interval
所以你检查一下:
这意味着你不会遇到以下情况:
.........[----------------]...........
^ ^
| |
start date end date
这也是不可接受的。但是根据你的代码const int durationHour = 1;
。所以每次会议都持续一个小时,这种制动情况对你来说应该不是问题。
无论如何,代码被制动的某种样本数据会很棒。