0

我有一个前开发人员编写的以下 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; }
}

该查询假设处理以下场景

  1. 给定一个在 ShiftStart 和 ShiftEnd 时间之间的 ScheduledTime 但不匹配同一城市的任何员工的约会 - (返回 true)
  2. 给定一个在 ShiftStart 和 ShiftEnd 时间之间具有 ScheduledTime 的约会,并且该班次的员工与客户在同一个城市(返回 True 并分配给员工)

如果客户与员工不在同一个城市,我们将预约分配为“未分配”,因为 scheduleTime 在员工轮班开始/结束时间范围内

如果客户与员工在同一个城市,我们会将约会分配给其中一名员工(firstOrdefault)并占用该时间段。

约会不能重叠(已分配)。未分配的不能相互重叠。

此查询用于工作(我被告知)。但现在它没有,我尝试重构它和其他各种路径,但都没有运气。我现在在第二周,只是不知道查询中的问题在哪里或如何编写。

如果我需要进一步发布任何内容,请告诉我。我已经验证了约会、轮班、城市都填充了有效数据,因此问题似乎与空数据或缺失数据无关。

4

1 回答 1

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;。因此,每次会议持续一小时,这种制动情况对您来说应该不是问题。

无论如何,代码正在崩溃的某种示例数据会很棒。

于 2013-10-26T22:43:56.800 回答