2

我有一个棘手的问题,我已经搞砸了几天,找不到最佳解决方案。

这些是我的表:

  • 地点
  • 站点节点

站点节点表包含代表层次结构的节点列表(使用嵌套集)。每个节点必须有一个或多个关联页面。每个站点必须有一个关联的错误页面和一个未找到的页面。

因此,一个页面必须要么属于一个节点,要么属于一个站点作为错误或未找到页面。我目前正在玩弄的解决方案是:

  1. 页表上的 parentType 和 parentId 字段,其中 type 可以是“node”、“site_error”或“site_notFound”,id 可以是站点或节点 id(以与类型相关的为准)。
  2. 页表上的nodeId 字段可以为空,然后是站点表上的errorPageId 和notFoundPageId 字段。

选项 #1 确保每个页面属于一个且仅属于一个其他实体,尽管实际上不能强制执行关系,因为 parentId 字段可以指向多个位置。

选项#2 更简洁,但它基本上是说该站点“属于”两个错误和未找到的页面,这可能是不好的做法。

有什么想法或建议吗?
谢谢,
杰克

4

5 回答 5

3

为错误或未找到页面制作虚拟站点节点。您可以根据您的第一个选项将它们标记为特定类型的节点。这将使创建通用处理程序机制变得更加容易。它还将使连接更简单,这将有助于提高数据库查询性能。此外,它允许您添加更多类型的“特殊”页面(可能是登录屏幕)或使其可配置,而无需修改数据库模式。

于 2009-02-11T17:02:56.630 回答
2

选项 #1 确保每个页面属于一个且仅属于一个其他实体,尽管实际上不能强制执行关系,因为 parentId 字段可以指向多个位置。

对。就关系理论而言,问题在于您的 " parentId" 列违反了第三范式,因为它的含义每行都会有所不同,具体取决于parentType(非键列)中的值。

如果单列可以包含某人的电话号码他们的生日,每行取决于其他一些标志,那么您将不会拥有一个设计正确的数据库。这是关于这个人的两个不同的事实,他们每个人都应该有自己的专栏。同样,将 site_id 或 node_id 存储在单个列中也会有同样的问题。

这是一个有缺陷的设计的另一个线索是您不能声明一个外键约束来指向两个引用表中的任何一个。

选项#2 更简洁,但它基本上是说该站点“属于”两个错误和未找到的页面,这可能是不好的做法。

我明白你为什么这么说,因为属于类 Rails 框架中的约定。但这些都是惯例;它们不一定是外键可以建模的唯一关系。您可以使一个实体在一个有一个关系中完全引用另一个实体。在这种情况下,外键反转方向。

我会说错误页面和未找到页面属于该站点在逻辑上是正确的,而不是相反。使它们成为强制性的方法是让另一个实体引用这些页面,并将NOT NULL约束应用于这些引用。这就是你所描述的。

CREATE TABLE site (
  . . .
  error_page_id     INT NOT NULL,
  notfound_page_id  INT NOT NULL,
  FOREIGN KEY (error_page_id)    REFERENCES pages (page_id),
  FOREIGN KEY (notfound_page_id) REFERENCES pages (page_id)
);

这满足了您的迫切需要,它是可执行的,并且是正常形式的。


@NXC建议为错误和未找到页面制作虚拟节点。尽管这允许将这些节点存储在节点层次结构中,但它无法强制站点必须具有这些页面。也就是说,可以在引用这些节点的情况下存储站点。

@Tony Andrews建议在每个页面中存储两列,site_idsite_node_id,并添加一个 CHECK 约束以确保其中一个是非空的。这似乎比parent_id/parent_type选项更好,但它仍然没有强制要求每个站点都必须有一个错误和一个未找到页面。

于 2009-02-11T17:27:46.880 回答
0

另一种选择是有 2 列 site_id 和 site_node_id 像这样:

create table pages
 ( page_id ... primary key
 , site_id references sites
 , site_node_id references site_nodes
 , ...
 , constraint site_or_node check (  site_id is null and site_node_id is not null
                                 or site_id is not null and site_node_id is null
                                 )
 );

现在,您可以使用参照完整性来确保每个页面都属于站点或节点,而不是两者。

于 2009-02-11T17:16:30.073 回答
0

选项 2 更有意义,并且在出现更多并发症时可以节省您的大脑。站点与错误/未找到页面的一对一关系使其非常适合外键约束。

于 2009-02-11T17:37:48.043 回答
0

选项 1 的修改。

包括两个单独的列,ParentNodeID 和 ParentSiteID。根据具体情况,将这两列之一保留为 NULL。现在您仍然可以为每个外键声明一个外键(引用)约束。

我不太了解 SiteNotFound 案例。在这种情况下,您可以将两个外键都保留为 NULL 吗?

您的加入和搜索会更简单。您还将遵守 1NF。这不是巧合。

您的选项 1 将来自不同域的值组合在一个字段中。这是糟糕的现场设计,IIRC 违反了 1NF。

于 2009-02-11T18:22:06.547 回答