enable/disable/delete 数据库行及其引用的最佳实践?
Best practices to enable/disable/delete database rows and its references?
处理删除或 enabling/deletion 行及其引用的 table 行的最佳做法是什么?
例如,假设我有一种非常简单的 'forum' 应用程序。
我有一个 table users
包含我的 webapp 帐户和 threads
包含用户创建的线程,还有一个 table comments
包含评论用户对主题发表评论。
现在,假设我想在注册时验证用户的电子邮件,然后再激活其帐户。最好的方法是什么?什么是最佳实践?也许通过只返回具有字段 is_active=true
的行的视图?使用 2 个分开的 table,例如 pre_users
(包含有待验证的用户)和 users
(已验证的用户)?
同样,您将如何处理想要暂停其帐户的用户?以及它的线程和评论?您会添加另一个标志 is_suspended
并更新视图以考虑该标志吗?如果它不是视图,而是 2 个单独的 table,我该如何处理引用?
另外,删除一个线程。假设在线程删除时我不希望线程被实际删除,因为我不希望发布评论的用户突然看不到他们的评论。如何处理?
解决此类问题的最佳做法是什么?
数据建模中的状态模式
在这种情况下,我们可以使用我命名为 Status Pattern in Data Modeling.
的模式
假设我们有一个具有许多 状态 的实体。例如 user
实体,它具有 pre-registered
、normal user
、deleted user
、suspended user
等
再例如,用户 Post
(如 Whosebug 帖子)有许多 状态,如 normal
、deleted by user
、deleted by moderator
、duplicated
、closed
等
假设我们要为 user
实体建模 statuses。在这种情况下,我们可以使用一个实体来保存所有状态类型(如 pre-registered
、normal user
、deleted user
、suspended user
)。我们可以将其命名为 User_Status_Types
并将所有用户状态类型放入其中。
因此,另一个实体需要持有任何用户状态。让我把它命名为User_Statuses
。它有 F.Ks 个 User
和 User_Status_Types
。
通过这种模式,我们可以保存用户的所有状态。
为了改进模式,我们可以在 User
中使用 F.K of User_Statuses
来显示用户最终状态。 (注意这不是循环依赖陷阱)
问题1:如果实体有两种不同类型的状态?
在这种情况下应该使用这种模式的时间。
问题 2:子实体(具有来自该实体的 F.K 的任何实体)的状态是否取决于实体的状态?
例如,如果我们想要 NOT 显示已删除用户的评论。在这种情况下,我们有两个选择:
方案1:我们可以写一个用户状态改变的触发器。如果用户状态更改为已删除,那么我们的触发器也会将所有用户评论状态更改为已删除。
选项2:在这个选项中,评论状态不会改变。 但是,我们可以在评论的select命令中使用额外的条件,让评论显示他们的父状态是正常的。
问题 3:如果状态变化的顺序很重要并且我们想在我们的数据模型中对它们进行建模。
在这种情况下,我们可以添加一个名为 User_Status_Types_Sequence
的新实体,它有来自 User_Status_Types
的 2 F.Ks 作为源和目标。这意味着源状态可以更改为目标状态。因此,我们可以 select 从数据库中对有效性进行排序,然后将其执行到我们的数据库中。
对于活动状态不影响唯一性的 tables(例如,用户由用户名或电子邮件地址标识,不可能有同一事物的活动和非活动版本)我使用可为空的日期时间字段来表示状态。例如,对于您的用户 table,我有一个 verified_at 列,该列最初设置为空,并在用户验证其帐户时设置为当前 date/time。用户帐户暂停也可以这样做。如果用户重新激活他们的帐户,我们只需将 suspended_at 字段设置为空。
如果您需要比简单 yes/no 更多的状态值,我会为状态值使用单独的字段,date/time 已更改。
如果您想跟踪更新历史(例如 activations/suspensions),最好在单独的 table 中进行。在这种情况下,您可以参考用户 table 的当前激活记录,这将比查询状态列更有效地使用 table 的索引。
在某些情况下,状态会影响唯一性。例如,在论坛中,用户可能能够存储任意数量的签名或头像,但一次只能有一个处于活动状态。在这些情况下,最好将当前数据与历史数据分开。例如,一个 table 用于签名,在用户中 table 一个外键来引用活动签名。 您应该能够更新任何行的状态,而不用担心其他行中的值。
避免级联状态,它们会破坏子项的先前状态,并在许多情况下使状态字段的使用几乎毫无意义。相反,在查询时与父 tables 结合以根据顶级状态进行过滤。
最后,数据中的状态是时态数据建模方向的一个步骤。我建议阅读该主题。
您可能需要更详细地了解您的业务需求,然后我们才能回答这方面的所有变化。
一般来说,当你在评论中与@reaanb 辩论时,我不会担心连接的性能 - 现代硬件和现代数据库可以处理大量记录。
我也会专注于在关系模型中对问题建模,而不用担心 "but isn't it more complex to include this check"。关注可理解性(设计与要求的接近程度?)。我真的不喜欢使用视图来捕获这些东西,因为当底层业务需求发生变化时,它们会使更改变得更加困难。
根据我的经验,您需要回答的最大问题是 "do the business requirements care about change over time"?
如果答案是 "no",那么您可以使用任何有意义的状态标志。例如,在用户 table 上,您可能有一个带有 "registered/validated/de-activated/deleted" 的状态列。这对编码来说相对简单 - 但您不能轻易回答 "on which date was this de-activated user validated?" 或 "what was the status of the user who posted this comment when they posted it".
这样的问题
如果需求确实关心时间,我喜欢的模型是在需要了解时间的行中添加"valid_from"和"valid_until"。 "current" 行有一个 null
valid_until 列。这使您可以随时了解数据的状态 - 但它确实会使您的查询更加复杂,尤其是当您连接多个 table 时。
但是,这意味着 - 例如 - 您可以允许尚未验证的用户发表 post 评论,但在他们验证其帐户之前隐藏这些评论。
这还意味着您可以创建报告,显示过去每个日期处于每个状态的用户数量、重新激活的非活动用户数量等。
通过将 "valid_from" 和 "valid_until" 添加到您的 "posts" table,您可以包含版本控制 - 也许您想表明评论是 post在 post?
的旧版本上编辑
最后,在一些复杂的应用程序中,我使用了 finite state machine 来管理状态之间的有效转换。这对您的系统来说可能有点矫枉过正。
处理删除或 enabling/deletion 行及其引用的 table 行的最佳做法是什么?
例如,假设我有一种非常简单的 'forum' 应用程序。
我有一个 table users
包含我的 webapp 帐户和 threads
包含用户创建的线程,还有一个 table comments
包含评论用户对主题发表评论。
现在,假设我想在注册时验证用户的电子邮件,然后再激活其帐户。最好的方法是什么?什么是最佳实践?也许通过只返回具有字段 is_active=true
的行的视图?使用 2 个分开的 table,例如 pre_users
(包含有待验证的用户)和 users
(已验证的用户)?
同样,您将如何处理想要暂停其帐户的用户?以及它的线程和评论?您会添加另一个标志 is_suspended
并更新视图以考虑该标志吗?如果它不是视图,而是 2 个单独的 table,我该如何处理引用?
另外,删除一个线程。假设在线程删除时我不希望线程被实际删除,因为我不希望发布评论的用户突然看不到他们的评论。如何处理?
解决此类问题的最佳做法是什么?
数据建模中的状态模式
在这种情况下,我们可以使用我命名为 Status Pattern in Data Modeling.
假设我们有一个具有许多 状态 的实体。例如 user
实体,它具有 pre-registered
、normal user
、deleted user
、suspended user
等
再例如,用户 Post
(如 Whosebug 帖子)有许多 状态,如 normal
、deleted by user
、deleted by moderator
、duplicated
、closed
等
假设我们要为 user
实体建模 statuses。在这种情况下,我们可以使用一个实体来保存所有状态类型(如 pre-registered
、normal user
、deleted user
、suspended user
)。我们可以将其命名为 User_Status_Types
并将所有用户状态类型放入其中。
因此,另一个实体需要持有任何用户状态。让我把它命名为User_Statuses
。它有 F.Ks 个 User
和 User_Status_Types
。
通过这种模式,我们可以保存用户的所有状态。
为了改进模式,我们可以在 User
中使用 F.K of User_Statuses
来显示用户最终状态。 (注意这不是循环依赖陷阱)
问题1:如果实体有两种不同类型的状态?
在这种情况下应该使用这种模式的时间。
问题 2:子实体(具有来自该实体的 F.K 的任何实体)的状态是否取决于实体的状态?
例如,如果我们想要 NOT 显示已删除用户的评论。在这种情况下,我们有两个选择:
方案1:我们可以写一个用户状态改变的触发器。如果用户状态更改为已删除,那么我们的触发器也会将所有用户评论状态更改为已删除。
选项2:在这个选项中,评论状态不会改变。 但是,我们可以在评论的select命令中使用额外的条件,让评论显示他们的父状态是正常的。
问题 3:如果状态变化的顺序很重要并且我们想在我们的数据模型中对它们进行建模。
在这种情况下,我们可以添加一个名为 User_Status_Types_Sequence
的新实体,它有来自 User_Status_Types
的 2 F.Ks 作为源和目标。这意味着源状态可以更改为目标状态。因此,我们可以 select 从数据库中对有效性进行排序,然后将其执行到我们的数据库中。
对于活动状态不影响唯一性的 tables(例如,用户由用户名或电子邮件地址标识,不可能有同一事物的活动和非活动版本)我使用可为空的日期时间字段来表示状态。例如,对于您的用户 table,我有一个 verified_at 列,该列最初设置为空,并在用户验证其帐户时设置为当前 date/time。用户帐户暂停也可以这样做。如果用户重新激活他们的帐户,我们只需将 suspended_at 字段设置为空。
如果您需要比简单 yes/no 更多的状态值,我会为状态值使用单独的字段,date/time 已更改。
如果您想跟踪更新历史(例如 activations/suspensions),最好在单独的 table 中进行。在这种情况下,您可以参考用户 table 的当前激活记录,这将比查询状态列更有效地使用 table 的索引。
在某些情况下,状态会影响唯一性。例如,在论坛中,用户可能能够存储任意数量的签名或头像,但一次只能有一个处于活动状态。在这些情况下,最好将当前数据与历史数据分开。例如,一个 table 用于签名,在用户中 table 一个外键来引用活动签名。 您应该能够更新任何行的状态,而不用担心其他行中的值。
避免级联状态,它们会破坏子项的先前状态,并在许多情况下使状态字段的使用几乎毫无意义。相反,在查询时与父 tables 结合以根据顶级状态进行过滤。
最后,数据中的状态是时态数据建模方向的一个步骤。我建议阅读该主题。
您可能需要更详细地了解您的业务需求,然后我们才能回答这方面的所有变化。
一般来说,当你在评论中与@reaanb 辩论时,我不会担心连接的性能 - 现代硬件和现代数据库可以处理大量记录。
我也会专注于在关系模型中对问题建模,而不用担心 "but isn't it more complex to include this check"。关注可理解性(设计与要求的接近程度?)。我真的不喜欢使用视图来捕获这些东西,因为当底层业务需求发生变化时,它们会使更改变得更加困难。
根据我的经验,您需要回答的最大问题是 "do the business requirements care about change over time"?
如果答案是 "no",那么您可以使用任何有意义的状态标志。例如,在用户 table 上,您可能有一个带有 "registered/validated/de-activated/deleted" 的状态列。这对编码来说相对简单 - 但您不能轻易回答 "on which date was this de-activated user validated?" 或 "what was the status of the user who posted this comment when they posted it".
这样的问题如果需求确实关心时间,我喜欢的模型是在需要了解时间的行中添加"valid_from"和"valid_until"。 "current" 行有一个 null
valid_until 列。这使您可以随时了解数据的状态 - 但它确实会使您的查询更加复杂,尤其是当您连接多个 table 时。
但是,这意味着 - 例如 - 您可以允许尚未验证的用户发表 post 评论,但在他们验证其帐户之前隐藏这些评论。
这还意味着您可以创建报告,显示过去每个日期处于每个状态的用户数量、重新激活的非活动用户数量等。
通过将 "valid_from" 和 "valid_until" 添加到您的 "posts" table,您可以包含版本控制 - 也许您想表明评论是 post在 post?
的旧版本上编辑最后,在一些复杂的应用程序中,我使用了 finite state machine 来管理状态之间的有效转换。这对您的系统来说可能有点矫枉过正。