2013-10-26 4 views
0

У меня есть следующий запрос LINQ, написанный бывшим разработчиком, и он не работает, когда это необходимо.LINQ Query возвращает false, когда это должно быть верно

 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. назначат С А ScheduledTime между А ShiftStart и ShiftEnd времени, но не соответствует ни сотрудников в то же city ​​- (Вернуться к списку)
  2. Учитывая назначение с запланированным временем между ShiftStart и ShiftEnd time И сотрудник для этот сдвиг находится в том же городе, что и заказчик (Return True AND Assign to the employee)

Если клиент НЕ находится в том же городе, что и работник, мы назначаем встречу как «Не назначенный», а также как запланированное время находится в пределах старта/времени начала работы сотрудников

Если клиент находится в одном городе с сотрудником, мы назначаем встречу одному из сотрудников (firstOrdefault) и занимаем этот временной интервал.

Назначения НЕ МОГУТ перекрываться (назначенные). Неназначенные не могут пересекаться друг с другом.

Этот запрос используется для работы (мне сказали). Но теперь это не так, и я попробовал рефакторинг и различные другие пути без везения. Я сейчас на второй неделе и просто не знаю, где проблема в запросе или как его написать.

Сообщите мне, если мне нужно опубликовать что-нибудь еще. Я проверил встречи, смены, все города заполнены действительными данными, поэтому проблема не связана с нулевыми или отсутствующими данными.

+2

Что-то, что помогает при публикации таких вопросов, включает в себя базовое определение других типов, участвующих в этом коде. Сотрудник, Назначение, Город и т. Д. –

+0

Должен ли я добавлять классы домена для Employee, Appointment? Класс репозитория - это оболочка для Entity Framework, которая является общей). – devfunkd

+0

Да, я вижу, по крайней мере, Employee, Назначение, Shift, Тип города, а также метод EntityFunctions.AddHours, который вы не предоставили, и ради краткости и релевантности вы можете опустить члены, которые не используются в коде. –

ответ

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;. Поэтому каждая встреча длится один час, и эта ситуация торможения не должна быть проблемой для вас.

В любом случае, некоторые образцы данных, где происходит торможение кода, будут отличными.

Смежные вопросы