Я пишу новое приложение с Rails, поэтому в каждой таблице есть столбец id. Какова наилучшая практика для применения ограничений домена с использованием внешних ключей? Я поделюсь своими мыслями и разочарованием.
Вот что я мог бы представить как "Путь Рельсов". Это то, с чего я начал.
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)
Проблема в том, что продукт одной компании может появиться в счете для другой компании. Я добавил (company_id: integer, а не NULL) в LineItems, как если бы я использовал только натуральные ключи и серийные номера, а затем добавил составной внешний ключ.
LineItems (product_id, company_id) references Products (id, company_id)
LineItems (invoice_id, company_id) references Invoices (id, company_id)
Это правильно ограничивает LineItems для одной компании, но кажется чрезмерно сложным и неправильным. company_id в LineItems является посторонним, потому что суррогатные внешние ключи уже уникальны во внешней таблице. Postgres требует, чтобы я добавил уникальный индекс для указанных атрибутов, поэтому я создаю уникальный индекс для (id, company_id) в продуктах и счетах, даже если 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, когда доступно целое число.
Существует ли чистый способ применения ограничений домена с помощью внешних ключей, как задумал Бог, но в присутствии суррогатов, не превращая схему и индексы в сложный беспорядок?