Повтарящо се събитие, по дефиниция, е събитие, което се повтаря на интервал; нарича се още периодично събитие. Има много приложения, които позволяват на своите потребители да настройват повтарящи се събития. Как системата за база данни управлява повтарящи се събития? В тази статия ще разгледаме един начин, по който се обработват.
Повтарянето не е лесно за приложенията да се справят. Това може да се превърне в ураганна задача, особено когато става въпрос за покриване на всеки възможен повтарящ се сценарий – включително създаване на събития на две седмици или тримесечие или позволяване на разсрочване на всички бъдещи случаи на събитие.
Два начина за управление на повтарящи се събития
Мога да се сетя за поне два начина за справяне с периодични задачи в модел на данни. Преди да ги обсъдим, нека бързо да разгледаме изискванията на тази задача. Накратко, ефективното управление означава:
- На потребителите е разрешено да създават редовни и повтарящи се събития.
- Ежедневни, седмични, двуседмични, месечни, тримесечни, двугодишни и годишни събития могат да се създават без ограничения за крайна дата.
- Потребителите могат да пренасрочват или отменят екземпляр на събитие или всички бъдещи екземпляри на събитие.
Имайки предвид тези параметри, идват на ум два начина за управление на повтарящи се събития в модела на данни. Ще ги наречем наивен и експертен начин.
Наивният начин: Съхраняване на всички възможни повтарящи се екземпляри на събитие като отделни редове в таблица. В това решение се нуждаем само от една таблица, а именно event
. Тази таблица има колони като event_title
, start_date
, end_date
, is_full_day_event
и т.н. start_date
и end_date
колоните са типове данни за времеви отпечатъци; по този начин те могат да приемат събития, които не продължават цял ден.
Плюсовете: Това е доста ясен подход и най-простият за изпълнение.
Против: Наивният начин има някои значителни недостатъци, включително:
- Необходимостта от съхраняване на всички възможни екземпляри на събитие. Ако имате предвид нуждите на голяма потребителска база, тогава е необходимо голямо пространство. Пространството обаче е доста евтино, така че тази точка няма голямо влияние.
- Много объркан процес на актуализиране. Да предположим, че събитие е пренасрочено. В този случай някой трябва да актуализира всички негови екземпляри. При разсрочване трябва да се извършат огромен брой DML операции, което създава отрицателно въздействие върху производителността на приложението.
- Обработка на изключения. Всички изключения трябва да се обработват грациозно, особено ако трябва да се върнете и да редактирате първоначалната среща, след като направите изключение. Например, да предположим, че премествате третия екземпляр на повтарящо се събитие напред с един ден. Ами ако впоследствие редактирате часа на първоначалното събитие? Вмъквате ли отново друго събитие в първоначалния ден и оставяте това, което сте посочили? Прекратяване на връзката на изключението? Опитайте да го промените по подходящ начин?
Event_id
– Тази колона се препраща отevent
таблица и действа като първичен ключ в тази таблица. Показва идентифициращата връзка междуevent
иrecurring_pattern
маси. Тази колона също така ще гарантира, че има максимум един повтарящ се модел за всяко събитие.Recurring_type_id
– Тази колона обозначава вида на повторението, независимо дали е ежедневно, седмично, месечно или годишно.Max_num_of_occurrances
– Има моменти, когато не знаем точната крайна дата за дадено събитие, но знаем колко събития (срещи) са необходими, за да се завърши. Тази колона съхранява произволно число, което определя логическия край за събитие.Separation_count
– Може да се чудите как може да се конфигурира двуседмично или двугодишно събитие, ако има само четири възможни стойности от тип повтаряне (дневно, седмично, месечно, годишно). Отговорът еseparation_count
колона. Тази колона означава интервала (в дни, седмици или месеци), преди да бъде разрешено следващото събитие. Например, ако събитие трябва да бъде конфигурирано за всяка друга седмица, тогава separation_count =“1” за да отговори на това изискване. Стойността по подразбиране за тази колона е „0“.recurring_type_id
ще бъде „седмично“.separation_count
ще бъде „1“.day_of_week
ще бъде „2“.Week_of_month
– Тази колона е за събития, които са планирани за определена седмица от месеца – т.е. първа, втора, последна, предпоследна и т.н. Можем да съхраняваме тези стойности като 1,2,3, 4,.. (от началото на месеца) или -1,-2,-3,... (от края на месеца).Day_of_month
– Има случаи, когато събитие е насрочено за определен ден от месеца, да речем 25-и. Тази колона отговаря на това изискване. Катоweek_of_month
, може да се попълни с положителни числа („7“ за 7-ия ден от началото на месеца) или с отрицателни числа ( „-7“ за седмия ден от края на месеца).recurring_type_id
ще бъде „ежемесечно“.separation_count
ще бъде „2“.day_of_month
ще бъде „11“.- Всички останали колони ще бъдат нулеви.
- Събития, които се случват на празници. Когато конкретен случай на събитие се случи на официален празник, трябва ли той автоматично да бъде преместен в работния ден непосредствено след празника? Или трябва да се отмени автоматично? При какви обстоятелства би се приложило едно от тези?
- Конфликти между събития. Ами ако определени събития (които се изключват взаимно) паднат в един и същи ден?
Експертният начин: Съхраняване на повтарящ се модел и програмно генериране на минали и бъдещи екземпляри на събития. Това решение разглежда недостатъците на наивното решение. Ще обясним подробно експертното решение в тази статия.
Предложеният модел
Създаване на събития
Всички планирани събития, независимо от техния редовен или повтарящ се характер, се регистрират в event
маса. Не всички събития са повтарящи се събития, така че ще ни трябва колона за флаг, is_recurring
, в тази таблица, за да посочите изрично повтарящи се събития. event_title
и event_description
колони съхраняват темата и кратко резюме на събитията. Описанията на събития не са задължителни, поради което тази колона може да бъде нула.
Както подсказват имената им, start_date
и end_date
колоните запазват началната и крайната дата на събитията. В случай на редовни събития, тези колони съхраняват действителните начални и крайни дати. Те обаче също така съхраняват датите на първото и последното появяване на периодични събития. Ще запазим end_date
колона като нула, тъй като потребителите могат да конфигурират повтарящи се събития без крайна дата. В този случай бъдещите събития до хипотетична крайна дата (да речем за една година) ще бъдат показани в потребителския интерфейс.
is_full_date_event
колона означава дали дадено събитие е целодневно събитие. В случай на целодневно събитие, start_time
и end_time
колоните ще бъдат нулеви; това е причината и двете колони да са нулеви.
created_by
и created_date
колоните съхраняват кой потребител е създал събитие и датата на създаването на събитието.
Следва parent_event_id
колона. Това играе основна роля в нашия модел на данни. Ще обясня значението му по-късно.
Управление на повторенията
Сега стигаме направо до основната формулировка на проблема:Ами ако се създаде повтарящо се събитие в event
таблица – т.е. is_recurring
флагът за събитието е „Y“?
Както беше обяснено по-рано, ние ще съхраняваме повтарящ се модел за събития, така че да можем да конструираме всички негови бъдещи събития. Нека започнем със създаване на recurring_pattern
маса. Тази таблица има следните колони:
Нека разгледаме значението на останалите колони по отношение на различните видове повторения.
Ежедневно повтаряне
Наистина ли трябва да улавяме модел за ежедневно повтарящо се събитие? Не, защото всички подробности, необходими за генериране на ежедневен модел на повторение, вече са регистрирани в event
таблица.
Единственият сценарий, който изисква модел, е, когато събитията са насрочени за алтернативни дни или на всеки X брой дни. В този случай separation_count
колона ще ни помогне да разберем модела на повторение и да извлечем допълнителни случаи.
Ежеседмично повтаряне
Необходима ни е само една допълнителна колона, day_of_week
, за да запаметите кой ден от седмицата ще се проведе това събитие. Ако приемем, че понеделник е първият ден от седмицата, а неделята е последният, възможните стойности биха били 1,2,3,4,5,6 и 7. При необходимост трябва да се направят подходящи промени в кода, който генерира отделни събития. Всички останали колони ще бъдат нулеви за седмични събития.
Да вземем класически тип седмично събитие:двуседмичното събитие. В този случай ще кажем, че се случва всяка алтернативна седмица във вторник, вторият ден от седмицата. И така:
Месечно повтаряне
Освен day_of_week
, изискваме още две колони, за да изпълним всеки сценарий на месечно повтаряне. Накратко, тези колони са:
Нека сега разгледаме по-сложен пример - тримесечно събитие. Да предположим, че една компания планира тримесечно събитие за прогнозиране на резултата за 11-ия ден от първия месец на всяко тримесечие (обикновено януари, април, юли и октомври). Така че в този случай:
В горния пример приемаме, че потребителят създава тримесечната прогноза за резултата през януари. Моля, имайте предвид, че тази логика на разделяне ще започне да се брои от месеца, седмицата или деня, когато е създадено събитието.
На подобни линии, полугодишните събития могат да се регистрират като месечни с
Годишното повтаряне е доста лесно. Имаме колони за определени дни от седмицата и месеца, така че се нуждаем само от една допълнителна колона за месеца от годината. Нарекли сме тази колона
Сега да стигнем до изключенията. Ами ако конкретен случай на повтарящо се събитие бъде отменен или пренасрочен? Всички такива случаи се регистрират отделно в
Нека да разгледаме две колони,
Освен тези две колони, всички останали колони действат по същия начин като в
Има приложения, които позволяват на потребителите да пренасрочват всички бъдещи случаи на повтарящо се събитие. В такива случаи имаме две възможности. Можем да съхраняваме всички бъдещи екземпляри в
С това решение можем да получим всички минали събития на събитие, дори когато моделът му на повторение е променен.
Има някои по-сложни области около повтарящи се събития, които не сме обсъждали. Ето две:
Какви промени трябва да направим, за да изградим тези възможности? Моля, кажете ни вашите мнения в секцията за коментари.separation_count
от „5“.Ежегодно повтаряне
month_of_year
.Обработка на изключения от повтарящи се събития
event_instance_exception
маса. Is_rescheduled
и is_cancelled
. Тези колони означават дали този екземпляр е пренасрочен за по-късна дата/час или е отменен изцяло. Защо имам две отделни колони за това? Е, просто помислете за събития, които първо са били разсрочени и след това напълно отменени. Това се случва и ние имаме начин да го запишем с тези колони. event
таблица.Защо да свързвате две събития чрез
parent_event_id
?event_instance_exception
(намек:не е приемливо решение). Или можем да създадем ново събитие с нови параметри за дата/час в event
таблица и я свържете с нейното по-ранно събитие (родителското събитие) посредством id_parent_event
колона. Как да подобрим обработката на повтарящи се събития?