An Event entity stores one or more Sessions. However, a Session is not a traditional entity with its own database table.
An Event contains a recurrence rule property defining when and how sessions recur. Here is an example of raw iCal data:
Thus, the above five day camp is not five entries in the database. The entire camp is a single entry, and the sessions are calculated on the fly when rendering or checking for collisions.
We will use Libraries to handle this, specifically TimePeriodLibrary|143 for recurrence rules, collisions, availability, etc. For example, a Session object will include a TimePeriodLibrary.TimeRange object.
If we change attributes of Sessions within a given Event (for instance, the Wednesday evening class of a week-long class will occur at a different location), then a separate database table of Exceptions will store edited values. When hydrating a list of Sessions via a stored recurrence rule, check if Exceptions exist for this Event, and then overwrite session data according to the Exceptions.
DO NOT attempt to search for event collisions manually. Use the TimePeriodLibrary’s IntersectsWith. This math is deceptively hard.
We need a separate database table to handle days off when nothing should be booked. For instance, holidays, scheduled maintenance, etc. This should block off every calendar (or every appropriate calendar). TimePeriodLibrary has a DaySeeker class to find the next available business day.