If you most often read events and do not mind a small additional saving, you can choose to materialize your events based on the rules in the new table. This table can be cleaned and restored if you want, based on the rules, or selectively re-populated as necessary.
Event 1 on saving will create one record with EventID: 1
Event 2, when saved, will create entries for the date range corresponding to the DOW property, with EventID: 2
Event 3 will do the same, but with its date range / DOW, with EventID: 3
You can use some fancy LINQ to determine which rows to add if you want, but the end result is that you need rows of physical instances for a very simple query.
When updating an event, you can simply delete all rows for this EventID and re-create them based on the changes.
Given the above, your read operation may be simple:
EventInstances.Where(i => i.Date >= startDate && i.Date <= endDate);
If you need slow / complex reads and fast writes, you will need to create this memory card every time you read.
UPDATE: some code to show what I mean
The logic for populating a table is the same logic that you could use to create a table in memory:
// slightly updated Event class public class Event { public int ID { get; set; } public DateTime StartDate { get; set; } public DateTime? EndDate { get; set; } public DayOfWeek[] DayOfWeekList { get; set; } public string Title { get; set; } } var startDate = new DateTime(2013, 9, 1); var endDate = new DateTime(2013, 9, 16); var totalDays = (int)endDate.Subtract(startDate).TotalDays + 1; // sample data, including a 4th event starting a while ago with no end date var events = new List<Event> { new Event { ID = 1, Title = "Event 1", StartDate = new DateTime(2013, 9, 15), EndDate = new DateTime(2013, 9, 15), DayOfWeekList = new[] { DayOfWeek.Sunday } }, new Event { ID = 2, Title = "Event 2", StartDate = new DateTime(2013, 9, 15), EndDate = new DateTime(2013, 9, 16), DayOfWeekList = new[] { DayOfWeek.Sunday, DayOfWeek.Monday } }, new Event { ID = 3, Title = "Event 3", StartDate = new DateTime(2013, 9, 1), EndDate = new DateTime(2013, 9, 30), DayOfWeekList = new[] { DayOfWeek.Tuesday, DayOfWeek.Thursday } }, new Event { ID = 4, Title = "Event 4", StartDate = new DateTime(2013, 1, 1), EndDate = null, DayOfWeekList = new[] { DayOfWeek.Wednesday } }, }; var eventsInRange = events .Where(e => e.StartDate <= endDate) .Where(e => (e.EndDate == null || e.EndDate.Value >= startDate )) // if you are getting from the database, force this data to be // retrieved since the following section would not work with the DB .AsEnumerable(); var daysInRange = Enumerable .Range(0, totalDays) .Select(i => startDate.AddDays(i)); var eventInstances = daysInRange .SelectMany(d => eventsInRange .Where(e => e.EndDate == null || d <= e.EndDate.Value) .Where(e => d >= e.StartDate) .Where(e => e.DayOfWeekList.Contains(d.DayOfWeek)) .Select(e => new { Date = d, Day = d.DayOfWeek, Event = e }));
If you want to fill out a table with this data to simplify queries, simply set the start date and end date based on a reasonable one (for example, start 1 year ago, at the end of 2 years).
If you want to re-populate only one event after the update, simply delete all entries for this event ID and eventsInRange
only update the event.