【问题标题】:How should I build the relationships between my tables?我应该如何建立表之间的关系?
【发布时间】:2018-07-17 18:33:18
【问题描述】:

我正在将发票组件构建到我的 Web 应用程序中。 在我的架构中,我们有某些客户可能希望开具发票的级别。

Projects -> Sites -> Jobs -> Phases -> Teams

每一个都是数据库中的表,并且与它们的父级有关系。

我计划构建一个 Items 表,该表将包含有关我们将如何为每个级别完成的工作开具发票的一般信息,即名称、默认价格、计量单位等.

然后,用户将创建一个 发票模型,他们可以将 Items 列表关联到该模型,以便这些可以重复使用。

这就是我的问题发挥作用的地方。当需要开发票时,我需要将 发票模型 与上述级别之一相关联。我不想为这些级别中的每一个创建一个到发票模型的链接表。我想以某种方式保持表之间的关系完整性。但是,如果将来有其他东西可以计费,我不想为了考虑到这个新的“计费级别”而进行巨大的数据库更改和/或代码更改。

我有没有办法在不创建新表将发票模型链接到关卡的情况下保持关系完整性?

【问题讨论】:

  • 多态关系丢失了参照完整性,但听起来这对您来说可能是一个不错的选择。
  • 我不确定我是否理解“我需要将发票模型与上述级别之一相关联”。如果发票是,正如您所说的那样,是一个项目列表,那不就是 关系吗?您有一个 Invoices 表、Items 表和一个 Invoice_Item (invoiceId, itemId) 表。您只有 一个“链接”表,而不是每个项目类型一个。
  • 你可以在单个表中对不同级别的表有多个可为空的 FK,因此完整性将在那里
  • @BillyStalnaker,专业人士将能够“附加”新实体类型而无需扩展您的表格。缺点是会丢失一些参照完整性,具体取决于实现。这可能是一个很好的阅读:hashrocket.com/blog/posts/…
  • @BillyStalnaker 是的,对于所有解决方案都是一样的,对于单个多态表,您必须多次阅读它,对于单独的表,您也将阅读所有这些表(它们总共等于单个表)

标签: php mysql invoice relational integrity


【解决方案1】:

可以实现多态关系,解决附加“n”个不同实体类型的问题。

据我所知,多态关系的缺点是,如果不损失一些引用完整性,就不可能实现。

https://hashrocket.com/blog/posts/modeling-polymorphic-associations-in-a-relational-database 是一个很好的读物。一种流行且最简单的实现是多态连接,引用自以下文章:

多态连接

将 acl 连接到资源的一种简单方法是使用两个 acl 表上的列:resource_type 和 resource_id。这种方法 由 Ruby on Rails 普及。 acl 表可以定义为 如下:

create table acl(
  id serial primary key,
  resource_type varchar not null,
  resource_id integer not null,
  -- other fields omitted
  unique(resource_id, resource_type)
);

检索文档 id:42 的 acl 的查询类似于 以下:

select *
from acl
where resource_type='document'
  and resource_id=42;

这种方法的一个严重问题是数据库非常有限 在数据完整性方面,由于缺少外键,它可以强制执行 约束。它可以确保一个资源没有多个 acl,但是 就这些。资源可能缺少 acl,而 acl 可以指向 缺少资源。


Exclusive Belongs To 方法是提高参照完整性的好方法,但需要为每个可能的实体类型创建一个新列。引自文章:

Exclusive Belongs To (AKA Exclusive Arc) 在这个模型中,acl 具有它可以属于的所有表的外键。

create table acl(
  id serial primary key,
  document_id integer references document,
  image_id integer references image,
  file_id integer references file,
  report_id integer references report,
  -- other fields omitted
  check(
    (
      (document_id is not null)::integer +
      (image_id is not null)::integer +
      (file_id is not null)::integer +
      (report_id is not null)::integer 
    ) = 1
  )
);

create unique index on acl (document_id) where document_id is not null;
create unique index on acl (image_id) where image_id is not null;
create unique index on acl (file_id) where file_id is not null;
create unique index on acl (report_id) where report_id is not null;

注意检查约束。这确保了一个acl属于 恰好是任何类型的一种资源。有了这种设计,acl 不能 孤立,但没有办法强制资源具有 acl。 部分唯一索引也很重要。限制唯一性 仅索引非空值可显着节省空间并 减少插入时的写操作。

【讨论】:

  • B-E-A-utiful 非常感谢!
【解决方案2】:

为了清楚地回答您的问题,如果不创建至少另外两个表,您将无法保持关系完整性,一个用于存储模型和项目之间的关系 id,另一个用于存储您要创建的项目的所有数据,在这种情况下,您最终将只剩下两张桌子,但现在可以治愈未来的痛苦。

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 2017-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多