我正在用Rails編寫一個新應用程序,所以我在每個表上都有一個id列。使用外鍵實施域約束的最佳做法是什麼?我將概述我的想法和挫敗感。如何在存在代理鍵時爲域約束定義複合外鍵?
下面是我想象的「The Rails Way」。這是我開始的。
Companies:
id: integer, serial
company_code: char, unique, not null
Invoices:
id: integer, serial
company_id: integer, not null
Products:
id: integer, serial
sku: char, unique, not null
company_id: integer, not null
LineItems:
id: integer, serial
invoice_id: integer, not null, references Invoices (id)
product_id: integer, not null, references Products (id)
的問題,這是從一個公司的產品可能會出現在一個不同的公司的發票。我向LineItems添加了一個(company_id:integer,不爲null),就像我只會使用自然鍵和連續字符一樣,然後添加一個組合外鍵。
LineItems (product_id, company_id) references Products (id, company_id)
LineItems (invoice_id, company_id) references Invoices (id, company_id)
這妥善限制了LineItem到一個單一的公司,但它似乎過度設計和錯誤的。 LineItems中的company_id是無關的,因爲代理外鍵在外表中已經是唯一的。 Postgres要求我爲引用的屬性添加一個唯一的索引,因此我在產品和發票中的(id,company_id)上創建了唯一索引,儘管id是唯一的。
下表自然鍵和一個串行發票號碼就不會有這種增加的複雜性,因爲引用的列都已經自然鍵,以便他們已經有一個唯一索引。
LineItems:
company_code: char, not null
sku: char, not null
invoice_id: integer, not null
我可以忽略LineItems表中的代理鍵,但這也似乎是錯誤的。爲什麼在數據庫中有一個已經存在的整數可以使用時加入char?此外,完全按照上述要求,我需要將company_code(一種自然的外鍵)添加到Products和Invoices。
妥協...
LineItems:
company_id: integer, not null
sku: integer, not null
invoice_id: integer, not null
不需要其它表自然外鍵,但它仍然是在焦炭在接合時有可用的整數。
有沒有乾淨的方式執行與外國鍵域約束像上帝打算,但在代理人的情況下,頭也不回的模式和索引到一個複雜的爛攤子?