Railsを使用して新しいアプリを作成しているので、すべてのテーブルにid列があります。外部キーを使用してドメイン制約を適用するためのベストプラクティスは何ですか?私の考えと欲求不満の概要を説明します。
これが私が「TheRailsWay」として想像するものです。それは私が始めたものです。
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:整数、nullではない)を追加しました。これは、自然キーとシリアルのみを使用する場合と同じように、複合外部キーを追加しました。
LineItems (product_id, company_id) references Products (id, company_id)
LineItems (invoice_id, company_id) references Invoices (id, company_id)
これにより、LineItemsは単一の会社に適切に制約されますが、過剰に設計されており、間違っているように見えます。LineItemsのcompany_idは、代理外部キーが外部テーブルですでに一意であるため、無関係です。Postgresでは、参照される属性に一意のインデックスを追加する必要があるため、idは単純に一意ですが、Products and Invoicesの(id、company_id)に一意のインデックスを作成しています。
参照される列はすでに自然キーであり、一意のインデックスがすでにあるため、自然キーとシリアル請求書番号を含む次の表では、このような複雑さは増していません。
LineItems:
company_code: char, not null
sku: char, not null
invoice_id: integer, not null
LineItemsテーブルの代理キーは無視できますが、これも間違っているようです。使用する整数がすでにあるのに、なぜデータベースをcharで結合させるのですか?また、上記とまったく同じように行うには、製品と請求書に自然外部キーであるcompany_codeを追加する必要があります。
妥協...
LineItems:
company_id: integer, not null
sku: integer, not null
invoice_id: integer, not null
他のテーブルに自然外部キーは必要ありませんが、使用可能な整数がある場合は、charで結合されます。
スキーマとインデックスを複雑な混乱に変えることなく、神が意図したような外部キーを使用してドメイン制約を適用するクリーンな方法はありますか?