2008-08-15 131 views
10

我必须创建类似于Google日历的东西,所以我创建了一个包含用户所有事件的事件表。设计日历系统,如Google日历

困难的部分是处理重新发生的事件,事件表中的行有一个event_type字段,告诉你它是什么类型的事件,因为一个事件可以只针对一个日期,或者是一个重新发生的事件事件每x天。

主要的设计挑战是处理重新发生的事件。

当用户查看日历时,使用月份视图,如何显示给定月份的所有事件?查询将会非常棘手,所以我认为创建另一个表并为每个事件创建一个行,包括重新发生的事件会更容易。

你们认为什么?

回答

3

我会说从ical标准开始。如果您将其用作您的模型,那么您将能够完成谷歌日历,展望,宏观(程序)的所有功能,并且可以实现与它们的即时集成。

从那里,时间骨头上你的ajax和JavaScript的cuz你不能有一个华丽的网络用户界面拖放和多个日历没有吨阿贾克斯和JavaScript。

0

我想我理解你的第二段意味着你正在考虑第二个事件表,每个事件发生时都有一行。我会避免这一点。

重复发生的事件应该有一个开始日期和一个停止日期(对于每X天都会持续的事件,“永远”可能为零)您必须决定要允许的频率类型 - 每个X天,每个月的第N天,每个给定的工作日等。

我可能倾向于两个表 - 一个是一次性事件,一个是重复性事件。你必须分别查询和显示两者。

如果我要解决这个问题(我会尽我所能避免重新发明这个轮子),我会寻找开源库,或者至少有开源项目的Calendars你可以看看。任何建议家伙?

1

从过去的经验来看,我会为每个发生的事件创建一个新记录,然后有一个引用前一个事件的列,以便您可以跟踪系列中的所有事件。

这有两个好处:

  1. 没有复杂的程序来制定下一个事件日期
  2. 个别事件可以被编辑,而不影响其他

希望这给你一些食物认为:)

1

你应该有一个开始日期,结束日期和到期日期。单日活动将具有相同的开始日期和结束日期,并且还允许您执行部分日活动。至于重新发生的事件,那么开始和结束日期将是同一天,但有不同的时间,然后你有枚举或表格指定重复频率(每日,每周,每月等)。

这可以让你每天说“这个事件每天出现”,“这个事件出现在每周的第二天”每周,“这个事件出现在每个月的第5天”每月,“这个事件出现在每年的第215天“,只要日期少于到期日。

1

我必须同意@ChanChan关于如何存储这些东西的ical规范。没有简单的方法来处理复发,尤其是那些有例外的复发。我已经构建并重建并重建了一个数据库来处理这个问题,并且我一直回到正确的位置。

根据用例创建一个从属表是一个不错的主意。准确计算出现时间的算法。 。 。这个,发生了。 。 。确实可能相当复杂。有没有摆脱它的运行,但值得考虑缓存结果。

1

@GateKiller

我还没有想过你编辑个别事件的情况。在这种情况下,你应该单独存储事件。

但是,当你这样做时,你将来会在多远存储事件?你选择了一个随意的日期吗?您是否在用户第一次浏览未来的月份/年份时自动生成新的事件?

另外,你如何处理用户想要编辑整个系列的情况。 “我们已经开了一个会每周二上午10时30分,但我们要启动会议上周三在8”

2

达伦,

那就是如何我设计我的事件表实际上,但是当考虑一下吧,假设我有10万用户创建了活动,这张桌子将会非常难受,特别是如果我要发送电子邮件来提醒人们他们的活动(活动也可能在一天中的特定时间! ),所以我可能每15分钟就会轮询一次这张桌子!

这就是为什么我想创建另一张表来展开所有事件/重新发生的事件,这样我就可以简单地点击该表并获得用户几个月的事件视图,而无需执行任何复杂的查询和业务逻辑,它也会使投票更加有效。

问题是,如果这个次表是次日或月?更有意义的是什么?由于用户可以查看的最大值是一个月的视图,因此我倾向于将表格写出给定月份的所有事件。

(当然,我将不得不维护用户可能对原始事件表进行的任何编辑的次表)。

ChanChan,

我有相同的排序功能,实际上设计的,但我只是指我怎么会去有关存储的事件,特别是如何处理重新发生事件。

5

试图存储每个事件的每个实例看起来好像是有问题的,而且也是不可能的。如果有人创建了“每星期四,永远”发生的事件,那么显然无法存储所有未来事件。

可能尝试按需生成未来事件,并仅在需要显示它们或发送有关它们的通知时填充未来事件。但是,如果您打算生成“按需生成”代码,为何不一直使用它?不必从事件表中提取数据,然后必须使用按需事件生成来填充尚未添加到表中的任何新事件,只需使用按需事件生成。最终结果将是一样的。有了这个方案,您只需要存储开始和结束日期以及事件频率。

我看不出有什么办法可以避免按需生成事件,所以我无法在事件表中看到该实用程序。如果你为了缓存而想要它,那么我认为你采取了错误的方法。首先,这是一个糟糕的缓存,因为无论如何你无法避免按需事件的产生。其次,无论如何,你应该可以缓存在更高的层次上。如果你想缓存,然后缓存生成的页面,而不是事件。

就提高轮询效率而言,如果每15分钟轮询一次,并且数据库和/或服务器无法处理负载,那么您已经注定失败。如果数据库无法处理太多的数据,将无法处理用户,而且不会出现更多频繁的投票,而且不会出汗。

5

如前所述,不要重新发明轮子,只是提高它。

结帐VCalendar,它是开源的,并且有PHP,ASP和ASP.Net(C#)!

你也可以检查出Day Pilot,它提供了一个用Asp.Net 2.0编写的日历。他们提供了一个精简版,你可以检查出来,如果它适合你,你可以购买一个许可证。

更新(09年9月30日):

当然,除非车轮坏了!另外,如果你喜欢的话,你可以放一个闪亮的新油漆(即:制作一个更好的用户界面)。但至少试图找到一些基础来建立,因为日历系统可能会很棘手(带有重复事件),并且已经完成了数千次。

0

undefined写道:

…这表将被打漂亮 辛苦,尤其是如果我要成为 向用户发送电子邮件,提醒 他们对事件的人(事件可以是 也是一天的特定时间!),所以我可能每15分钟就会轮询一次这张桌子!

为通知创建一个表。只是投票。

更新事件(循环或其他)时更新通知表。

编辑:数据库视图可能不违反正常形式,如果这是一个问题。但是,您可能需要跟踪哪些通知已发送,哪些尚未发送到任何地方。

0

Derek Park, 我会在表格中创建一个事件的每个实例,并且这个表格会每个月重新生成一次(因此任何事件被设置为'永远'重新启动'会提前一个月重新生成使用Windows服务或可能在SQL服务器级别)。 轮询不仅每15分钟进行一次,可能只是针对与电子邮件通知相关的民意调查。当有人想要观看他们的活动一个月时,我将不得不对所有事件进行研究,重新发生事件并找出要显示的事件(因为重新发生的事件可能在6个月前创建,但涉及用户正在查看的一个月)。我不太在意拥有一个完美规范化的数据库,我正在考虑创建一个辅助表的事实已经打破了其中的一条规则。我的核心数据库表遵循'规则',但我并不介意在有利于性能的情况下创建辅助表/列。

0

这就是我设计我的事件表的方法,但是当我想到它时,假设我有创建活动的100K用户,这张表会很难打到,特别是如果我要发送电子邮件提醒人们他们的活动(活动可以在一天中的特定时间!),所以我可能会每15分钟投票一次这张桌子!

数据库做处理数据集的异常作业,所以我不会太担心这一点。你应该做的就是将它用作主表,然后在事件过期后将它们移动到另一个表(如存档)。

接下来你要尝试的是尽可能少地查询数据库,因此将信息移入缓存层(如velocity),并将数据保存到数据库。

然后,您可以将信息分区到多个数据库以进行扩展。即服务器1上存在用户1-10000个日历,服务器2上存在10001 - 20000等。

这就是我如何扩展这样的解决方案,但我仍然认为我提出的原始解决方案是要走的路,这只是你如何规模化而成的问题。

2

蛮力十岁上下,但仍合理的方法是建立在单一事件表一个新行定期事件的每个实例,都指向不将事件在系列,但前面这第一个系列中的事件。这可以简化选择和/或删除特定系列中的所有元素,因为您可以根据父级ID进行选择。它还允许用户删除系列中的单个项目,而不影响其余项目。

此查询获取你该元素3启动系列:

SELECT * FROM events WHERE id = 3 OR parentid = 3 

要获得所有项目本月,假设你有一个开始日期,并在你的事件表的结束日期,你倒是需要做的是:

SELECT * FROM events WHERE startdate >= '2008-08-01' AND enddate <= '2008-08-31' 

处理一系列的创建/修改程序就不会很困难,但它确实将取决于设置要提供你怎么认为这将是该功能用过的。如果你想区分系列和事件,你可以在你的事件上有一个单独的系列表和一个可为空的series_id,让你可以自由地处理个别事件,同时仍然保留对你的系列的控制权。

1

我正在处理这个问题,并且我已经完全分开了iCalendarrfc 2445)直到阅读此主题,所以我不知道这将如何以及将不会与其整合。无论如何,我现在提出的设计看起来像这样:

  • 你不可能存储所有的循环事件的实例,至少不会发生之前,所以我只有一个表将事件的第一个实例存储为实际日期,可选过期以及可以为空的repeat_unit和repeat_increment字段来描述重复。对于单个实例,重复字段为空,否则单位将是“日”,“周”,“月”,“年”,增量仅仅是要添加到下一次出现的开始日期的单位的倍数。
  • 如果您需要与模型中的其他实体建立关系,则存储过去的事件似乎很有用,即使这样,在每种情况下都不需要有明确的“事件实例”表。如果其他实体已经有日期/时间“实例”数据,那么该事件的外键(或多对多连接表)最有可能就足够了。
  • 要做“改变这个实例”/“改变所有未来实例”,我打算重复这些事件并过期。因此,要更改单个实例,您将在最后一次出现时过期旧的副本,为更改后的新发生的独特副本复制副本,并在下列情况下重复发送原始副本未来。更改所有未来的实例是相似的,您只需要将原始文件过期,并根据更改和授权详细信息制作新的副本。

这两个问题我有这样的设计见到目前为止是:

  1. 它使MWF类型的事件很难代表。这是可能的,但是迫使用户创建三个单独的事件,每个事件每周重复M,W,F,并且他们想要作出的任何更改都必须单独完成。这些事件在我的应用程序中并不是特别有用,但它确实给模型留下了一个瑕疵,使得它不如我想要的那么普遍。
  2. 通过复制事件进行更改,可以中断它们之间的关联,这在某些情况下可能很有用(或者,也可能偶尔会出现问题)。事件表理论上可以包含一个“copied_from”id字段,用于跟踪一个事件发生的地方,但我还没有完全想到这样的事情会有多么有用。首先,父/子层次关系对于从SQL进行查询是一种痛苦,所以好处将需要相当大的重量才能超过查询数据的成本。我想可以使用nested-set

最后,我认为这是可能计算采用直板SQL对于给定的时间跨度的事件,但我还没有制定出具体细节,我想查询通常最终会过于麻烦是值得的。然而,对于论证起见,你可以使用下面的表达式来计算的差异月给出的年份和月份之间的事件:

(:month + (:year * 12)) - (MONTH(occursOn) + (YEAR(occursOn) * 12)) 

大厦的最后一个例子,你可以使用MOD以确定是否差异月是正确的多:

MOD(:month + (:year * 12)) - (MONTH(occursOn) + (YEAR(occursOn) * 12), repeatIncrement) = 0 

反正这是不完美(它不会忽略过期事件,在开始/结束时间为事件等不因子),所以它仅作为一个激励的例子。一般来说,尽管我认为大多数查询最终会变得太复杂。您最好查询在给定范围内发生的事件,或者不要在范围之前过期,并使用代码而不是SQL来计算实例本身。如果你真的想要数据库进行处理,那么存储过程可能会让你的生活变得更容易。

0

Ra-Ajax Calendar starter-kit以处理RenderDate事件为例,它可以修改具体的日期。虽然“反复出现的事件”更多的是算法上的事情,并且在这里,我怀疑很少有日历会帮助你很多......