我正在尝试使用C#开发一个基于调度器和日历的事件应用程序。其中一个关键需求是在数据库中表示循环事件。
最佳的数据库表示方式是什么?
更多细节:
在创建事件时,我还向某些用户发送邀请,并且被邀请者只能在指定的时间窗口(会议持续时间)内登录参加会议,或者当被邀请者试图在会议开始前5分钟登录时可以拒绝登录。
我正在尝试使用C#开发一个基于调度器和日历的事件应用程序。其中一个关键需求是在数据库中表示循环事件。
最佳的数据库表示方式是什么?
更多细节:
在创建事件时,我还向某些用户发送邀请,并且被邀请者只能在指定的时间窗口(会议持续时间)内登录参加会议,或者当被邀请者试图在会议开始前5分钟登录时可以拒绝登录。
在SQL Server中,sysjobs、sysjobsschedule和sysschedules表非常适合这个作业。我不会重新发明轮子,只需复制它们的设计。
以下是来自sysschedules
的一些重要字段:
freq_type
此计划运行工作的频率。
1 = 仅一次
4 = 每天
8 = 每周
16 = 每月
32 = 每月,相对于freq_interval
64 = SQL Server Agent服务启动时运行
128 = 计算机处于空闲状态时运行
freq_interval
执行作业的日期。取决于freq_type的值。默认值为0,表示未使用freq_interval。
1(一次) freq_interval未使用(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)
freq_subday_type
用于确定freq_subday_interval的单位。可以是以下值之一:
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_type为8、16或32时使用freq_recurrence_factor。如果此列包含0,则不使用freq_recurrence_factor。
嗯,为了存储循环规则本身,你可以使用一个简化版本的RFC 5545(我建议你大幅简化它)。除此之外,这将使导出到其他应用程序变得很容易。
在做出这个决定后,对于数据库方面,您需要确定是否要存储每个事件发生,还是只需存储重复事件的一条记录,并在需要时扩展它。显然,当你已经扩展了所有内容时,查询数据库会更容易--但维护起来就更困难。
除非你喜欢编写一些可能难以测试的相当复杂的SQL语句(并且你需要针对各种角落案例有大量单元测试),否则我建议您使数据库本身相对“愚笨”,并在像Java或C#这样的语言中编写大部分业务逻辑--当然,这取决于您的数据库,它们都可能被嵌入存储过程中。
另一件您需要考虑的事情是,是否需要处理事件的异常情况 - 即一系列事件中的一个更改时间/位置等。
我有一些日历方面的经验(我花了大部分时间在通过ActiveSync开发Google Sync的日历模块上),我应该警告您,事情很快就会变得非常复杂。任何你认为不在范围内的事情都是一种福音。特别是,您是否需要在多个时区中工作?
哦,最后--当您使用日历操作进行实际算术运算时,请非常小心。如果你要使用Java,请使用Joda Time而不是内置的Calendar
/Date
类。它们会给你带来很多帮助。
recurs_weekdays
对于每周和每月的循环,此字段存储发生循环的工作日。
1=星期日
2=星期一
4=星期二
8=星期三
16=星期四
32=星期五
64=星期六
例如:
每4周的星期六和星期日:
类似地,每6个月的第一个星期五是:
没有一个字段的含义取决于另一个字段的值。
在用户界面方面,我让用户指定日期、开始时间、结束时间。然后,他们可以指定除了“无”之外的循环类型。如果是这样,应用程序将扩展网页的相关部分,以向用户提供上述所需的选项,看起来很像Outlook选项,但每天循环下没有“每个工作日”(在每周一至周五的每周循环中已经包含),也没有年度循环。如果有循环,我还要求用户指定一个今天之内的结束日期(用户希望这样,并且简化了我的代码)- 我不做无限期循环或“结束后##次出现”。
我将这些字段与用户选择存储在我的事件表中,并在计划表中展开所有发生。这有助于冲突检测(我实际上正在做设施预订应用程序)和编辑单个事件或重构未来事件。
我的用户都在CST时区,我感谢上帝。这是一个有用的简化,如果将来的用户群会超出这个范围,那么我可以在那时解决它,作为一个独立的任务。
更新 自从我第一次写这篇文章以来,我添加了“每个工作日”的每日事件。我们的用户有点难以理解,他们认为你可以使用每周循环来处理从本周四到下周二仅在工作日发生的事件。即使已经有另一种方法可以做到这一点,但对他们来说更直观。
我也一直在考虑这个问题,尽管还没有实现,但以下是我对一个简单解决方案的想法。
在设置重复事件时,让用户指定“结束日期”,并为每个日期创建单独的事件(基于重复选项)。由于这是一个重复事件,为每个事件设置一个唯一的“重复ID”。此ID将用于标记事件为重复事件,如果您更改未来的事件,可以提示用户通过删除并使用新的“重复ID”重新创建重复事件来将更改应用于其余未来事件,这也将区分此重复事件与先前已更改的事件。
希望这有意义,并希望得到任何评论。
我会将重复事件记录为数据库中的两个不同事物。首先,在一个事件表中,记录每个事件的每次发生。其次,有一个重复事件表,其中记录您要求设置重复事件的详细信息。开始日期、周期性、发生次数等。
然后,您可以考虑通过将重复事件的PK作为FK放入每个事件记录中来将所有内容绑定在一起。但更好的设计是将事件表规范化为两个表,一个只是事件的基本信息,另一个包含详细信息,现在可以引用多个事件。这样,每个事件记录(无论是重复还是非重复)都具有对事件详细信息表的PK的FK。然后在事件详细信息中,记录重复事件的PK以及议程、被邀请者等。重复记录不驱动任何操作。例如,如果您想要列出所有重复事件的列表,则需要查找具有对重复事件的非空FK的所有事件详细信息。
您需要小心地同步所有这些内容,以便在重复数据更改时插入或删除事件。
除此之外
这是否包括“非常要求”?
“如果您希望,这将使其易于导出到其他应用程序。”
所述要求是否包括“必须轻松导出日历到其他应用程序”?我的印象是问题仅涉及构建第一个应用程序。
话虽如此,我的回答是:
您需要限制自己/用户可以支持的“重复性”类型。 如果您/用户想要最终获得可用的应用程序,“以上所有”或“没有限制”将不是有效的答案。