Рабочие часы работы в SQL / C # - PullRequest
2 голосов
/ 08 июня 2010

По какой-то причине у меня огромный мозг пердит. У меня есть таблица с «Часами работы» для бизнеса. Стол имеет: - день (понедельник = 1, воскресенье = 7) - Начальное время - Время окончания

Я пытаюсь выяснить, как написать самый чистый код (используя Linq to SQL), который будет проверять, не перекрываются ли часы при отправке новых часов, и соответственно изменять все записи. Например, если в базе данных уже есть эти записи: - Начало = 8 утра, Конец = Полдень - Начало = 14:00, Конец = 17:00

И кто-то добавляет: - Начало = Полдень, Конец = 6 вечера

Я хочу, чтобы код выяснил, как объединить эти 3 записи, и оставил меня с одной записью. Но мне также нужно иметь возможность комбинировать только при необходимости, чтобы кто-то вставил вместо этого: - Начало = Полдень, Конец = 13:00 * 1007

Тогда я получу 2 записи (первая будет изменена).

Как я и сказал ... Я просто не могу обернуться вокруг этого. Помощь

1 Ответ

2 голосов
/ 08 июня 2010

Я бы посоветовал вам немного изменить представление времени, чтобы иметь свойство Length вместо EndTime.

class TimeInterval
{
    public int Day { set; get; }
    public DateTime StartTime { set; get; }
    public int Length { set; get; }
}

Поскольку мы заинтересованы в поиске перекрывающихся интервалов, следующие методы будут удобны, я бы поместил их в класс TimeInterval.

public int StartMinuteInWeek()
{
    return Day * 24 * 60 + StartTime.Hour * 60 + StartTime.Minute;
}

public int EndMinuteInWeek()
{
    return StartMinuteInWeek() + Length;
}

Тогда вам просто нужно найти любой TimeInterval, который перекрывает ваш новый временной интервал. Вы должны знать, что новый интервал может расширять любой существующий, или даже объединять два отдельных интервала, или просто содержаться в уже определенном интервале.

Чтобы получить запись, которая накладывается на начало интервала, используйте следующий запрос:

var startOverlap = (from rec in intervals
    where rec.StartMinuteInWeek() <= timeInterval.StartMinuteInWeek() && rec.EndMinuteInWeek() >= timeInterval.StartMinuteInWeek()
    select rec).FirstOrDefault();

timeInterval - это новый интервал, который вы пытаетесь добавить.

для конечного перекрытия используйте следующее:

var endOverlap = (from rec in intervals
    where rec.StartMinuteInWeek() <= timeInterval.EndMinuteInWeek() && rec.EndMinuteInWeek() >= timeInterval.EndMinuteInWeek()
    select rec).FirstOrDefault();

Если startOverlap равен нулю, то в начале интервала перекрытия нет. То же самое для endOverlap. Если startOverlap == endOverlap, то новый интервал полностью связан внутри уже существующего интервала.

Я определил StartTime как тип DateTime, хотя меня интересует только часть времени, вы можете изменить это, если хотите, чтобы два поля назывались Hour и Minute или, возможно, одно единственное поле, которое представляет начальную минуту в неделя интервала.

EDIT

Как я уже упоминал в своем комментарии, я понял, что новый временной интервал может перекрывать несколько уже определенных интервалов. Например, если обычно операция идет с 8:00 до 20:00 и останавливается в обеденное время, а теперь определяется новый временной интервал, который проходит всю неделю 24x7, тогда новый временной интервал будет содержать 14 интервалов.

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

Чтобы узнать, перекрывает ли новый интервал старый, я собираюсь определить этот удобный метод в классе TimeInterval.

public bool IsInsideInterval(int minuteInWeek)
{
    return minuteInWeek >= StartMinuteInWeek() &&
        minuteInWeek <= EndMinuteInWeek();
}

Теперь я выясняю все интервалы, что его начальная минута или конечная минута находятся внутри нового интервала.

var overlaps = (from rec in intervals where
    newInterval.IsInsideInterval(rec.StartMinuteInWeek()) ||
    newInterval.IsInsideInterval(rec.EndMinuteInWeek())
    select rec).ToList();

И теперь вы должны убедиться, что новые пределы интервалов в порядке.

foreach (TimeInterval rec in overlaps)
{
    if (rec.StartMinuteInWeek() < newInterval.StartMinuteInWeek())
    {
        newInterval.Day = rec.Day;
        newInterval.StartTime = rec.StartTime;
    }
    if (rec.EndMinuteInWeek() > newInterval.EndMinuteInWeek())
    {
        // You have to calc the Length being careful to not count twice the minutes that overlaps.
        newInterval.Length = newInterval.Length + rec.Length - (newInterval.EndMinuteInWeek() - rec.StartMinuteInWeek());
    }
}

Наконец, вы можете удалить все интервалы в overlaps и затем вставить newInterval

...