Каков наилучший способ представления "повторяющихся событий" в базе данных?

Я пытаюсь разработать приложение событий, зависящее от планировщика и календаря, в C#, для которого решающее требование-представлять повторяющиеся события в базе данных. Каков наилучший способ представления повторяющихся событий в базе данных?

Подробнее:

при создании события я также отправляю приглашения определенным пользователям, и приглашенным должно быть разрешено войти в собрание только в течение указанного окна (продолжительность собрания) или может быть отклонено вход когда приглашенный пытается войти, скажем, за 5 минут до запланированного начала собрания.

6 ответов


на sysjobs, sysjobsschedule и sysschedules таблицы в SQL Server делают это довольно хорошо. Я не буду изобретать колесо, я просто скопирую их дизайн.

вот некоторые из важных полей из sysschedules

аргумента freq_type

Как часто выполняется задание для этого расписания.

1 = только один раз

4 = день

8 = еженедельника

16 = ежемесячно

32 = ежемесячно, относительно freq_interval

64 = запускается при запуске службы агента SQL Server

128 = запускается, когда компьютер простаивает

аргумент

дней выполнения задания. Зависит от значения freq_type. Значением по умолчанию является 0, что означает, что аргумент не используется. Значение эффекта freq_type на аргумент

1 (один) аргумент не используется (0)

4 (ежедневно) каждые freq_interval дней

8 (еженедельно) freq_interval является одним или несколькими из следующих: 1 = воскресенье 2 = понедельник 4 = вторник 8 = среда 16 = четверг 32 = пятница 64 = суббота

16 (ежемесячно) в freq_interval день месяца

32 (ежемесячно, относительно) freq_interval является одним из следующих: 1 = воскресенье 2 = Понедельник 3 = вторник 4 = Среда 5 = четверг 6 = пятница 7 = Суббота 8 = день 9 = будний день 10 = выходной день

64 (запускается при запуске службы агента SQL Server) freq_interval не используется (0)

128 (работает, когда компьютер простаивает) freq_interval не используется (0)

повторов задачи

единицы измерения аргумент Может быть одним из следующих значений: Описание Значения (Единица измерения)

1 в указанное время

2 секунд

4 минуты

8 часов

freq_subday_interval

количество периодов freq_subday_type, возникающих между каждым выполнением задания.

freq_relative_interval

когда freq_interval происходит в каждом месяце, если freq_interval 32 (ежемесячный родственник). Может быть одним из следующих значений:

0 = freq_relative_interval не используется

1 = Первая

2 = Вторая

4 = третья

8 = четвертая

16 = последний

freq_recurrence_factor

число недель или месяцев между запланированным выполнением задания. freq_recurrence_factor используется, только если freq_type равен 8, 16 или 32. Если этот столбец содержит 0, freq_recurrence_factor неиспользованный.


ну, чтобы сохранить само правило повторения, вы можете использовать сокращенную версию RFC 5545 (и я действительно предлагаю вам сократить его сильно). Помимо всего прочего, это позволит легко экспортировать в другие приложения, если вы хотите.

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

Если вы не хотите писать довольно сложный SQL, который может быть трудно проверить (и вам понадобится много модульных тестов для всех видов угловых случаев) я бы предложил вам сделать саму базу данных относительно "тупой" и написать большую часть бизнес-логики на языке Java или C# - любой из которых может быть встраиваемый в хранимые процедуры в зависимости от вашей базы данных, конечно.

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

у меня есть некоторый опыт работы с календарем (я провел большую часть прошлого года, работая над календарем бит Google Sync через ActiveSync), и я должен предупредить вас, что все усложняется действительно быстро. Все, что вы можете считать "вне сферы действия", является благословением. В частности, нужно работать в нескольких часовых поясах?

О, и, наконец, - будьте очень, очень осторожны, когда вы делаете фактическую арифметику с календарными операциями. Если вы собираетесь использовать Java, пожалуйста использовать Джода Времени а не встроенный Calendar/Date классы. Они тебе очень помогут.


принятый ответ здесь слишком запутан. Например, если событие происходит каждые 5 дней, 5 хранится в freq_interval, но если это происходит каждые 5 недель, 5 хранится в freq_recurrence. Самая большая проблема заключается в том, что freq_interval означает три разные вещи в зависимости от значения freq_type (количество дней между вхождениями для ежедневного повторения, день месяца для ежемесячного повторения или дни недели для еженедельного или ежемесячного относительного). Кроме того, 1,2,4,8... последовательность типов используется, когда это не нужно и менее чем полезно. Например, freq_relative_interval может быть только "из" возможные значения. Это соответствует раскрывающемуся списку или вводу типа переключателя, а не вводу типа флажка, где можно выбрать несколько вариантов. Для кодирования и для читаемости человека эта последовательность встает на пути и просто использует 1,2,3,4... проще, эффективнее, уместнее. Наконец, большинство приложений не нужны интервалы subday (событий происходит несколько раз в день - каждые столько-то секунд, минут или часов).
Но, сказав Это, этот ответ помог мне уточнить мои мысли о том, как я это делаю. После смешивания и сопоставления его с другими статьями и исходя из того, что я вижу в интерфейсе календаря Outlook и нескольких других источников, я придумываю это:

рецидивирует
0=Нет повторение
1=день
2=еженедельно
3=ежемесячно

recurs_interval
вот сколько периодов между повторениями. Если событие повторяется каждые 5 дней, это 5 и рецидивирует будет 1. Если событие повторяется каждые 2 недели, это будет 2 и рецидивирует будет 2.

recurs_day
Если пользователь выбрал ежемесячный тип повторения, в заданный день месяц (например, 10-й или 14-й). Это этой даты. Значение равно 0, если пользователь не выбрал месяц или определенный день повторения месяца. В противном случае значение равно от 1 до 31.

recurs_ordinal
если пользователь выбрал ежемесячный тип повторения, но порядковый тип дня (например: первый понедельник, второй четверг, последняя пятница). У этого будет порядковый номер. Значение равно 0, если пользователь не выбрал этот тип повторение.
1=первая
2=второй
3=Третья
4=Четвертая
5=Последняя

recurs_weekdays
для еженедельного и ежемесячно-порядкового повторения это хранит будние дни, где повторение происходит. 1=воскресенье
2=Понедельник
4=вторник
8=среда
16=четверг
32=пятница
64=суббота

Итак, примеры:
Так, каждые 4 недели в субботу и воскресенье будь

  • повторяется = 2 = = > еженедельное повторение
  • recurs_interval = 4 ==> каждый 4 недели
  • recurs_weekdays = 65 = = > (суббота=64 + воскресенье=1)
  • recurs_day и recurs_ordinal = 0 ==> не используется

аналогично, каждые 6 месяцев в первую пятницу месяца будет

  • повторяется = 3 = = > ежемесячное повторение
  • recurs_interval = 6 ==> каждый 6 месяцы
  • recurs_ordinal = 1 ==> при первом появлении
  • recurs_weekdays = 32 = = > пятницы

ни одно из этих дел не имеет поля, которое означает три совершенно разные вещи в зависимости от значения другого поля.

на стороне пользовательского интерфейса вещи, я позволить пользователю указать дату, время начала, Время окончания. Затем они могут указать, требуется ли им тип повторения, отличный от none. Если это так, приложение расширяется соответствующий раздел веб-страницы, чтобы дать пользователю параметры, необходимые для материала выше, очень похож на параметры Outlook, за исключением того, что нет "каждый будний день" в ежедневном повторении (что является избыточным с еженедельным повторением на каждый пн-пт), и нет ежегодного повторения. Если есть повторение, то я также требую от пользователя указать конечную дату, которая находится в течение одного года сегодня (пользователи хотят, чтобы это было так, и это упрощает мой код) - я не делаю бесконечное повторение или " конец после появления."

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

мои пользователи все в CST, и я благодарю Господа за это. Это полезное упрощение, и если в будущем база пользователей будет расширяться дальше этого, тогда я смогу понять, как с ней справиться, как с хорошо отделенной задачей.

обновление Поскольку я впервые написал это, я добавил ежедневное появление с "каждым будним днем". Нашим пользователям было немного трудно думать, что вы можете использовать еженедельные повторения для событий, происходящих с четверга одной недели до вторника на следующей неделе и только в будние дни. Это было более интуитивным для них, чтобы иметь это, даже если бы было уже другой способ, которым они могли это сделать.


Я тоже думал об этом, хотя и не реализовал его, но это мои мысли для простого решения.

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

надеюсь, что это имеет смысл и хотел бы каких-либо комментариев.


Я бы записал повторяющиеся события как две отдельные вещи в базе данных. Прежде всего, в таблице событий запишите каждое событие. Во-вторых, есть таблица повторов, в которой вы записываете детали, которые вы просите настроить повторяющееся событие. Дата начала, периодичность, количество вхождений и т. д.

тогда вы можете подумать о том, чтобы связать все это вместе, поместив PK рецидивов в каждую из записей событий как FK. Но лучше бы нормализовать таблицу событий в две таблицы, одна из которых является только голыми костями события, и одна, которая имеет детали, которые теперь могут относиться к нескольким событиям. Таким образом, каждая запись события, повторяющаяся или нет, имеет FK к PK таблицы eventdetails. Затем в eventdetails запишите ПК рецидивов где-то вместе с повесткой дня, приглашенными и т. д. Рекуррентная запись ничего не управляет. Например, если вам нужен список всех повторяющихся событий, просмотрите eventdetails для все события с ненулевым FK для повторений.

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


"помимо всего прочего"

включает ли это "сами требования" ?

"что позволит легко экспортировать в другие приложения, если хотите."

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

Что сказал, мой собственный ответ :

нужно ограничить самостоятельно / ваш пользователь по типам "рекуррентности" ваша система сможет поддерживать. И "все вышеперечисленное "или" без ограничений " не будет действительным ответом, если вы/ваш пользователь хотите(ы) в конечном итоге использовать приложение.