Общая таблица «один ко многим» для нескольких объектов - PullRequest
6 голосов
/ 19 мая 2010

Предположим, у меня есть две таблицы: Клиент и Продавец. Я хочу иметь общую таблицу адресов для адресов клиентов и поставщиков. Клиенты и поставщики могут иметь от одного до нескольких адресов.

Вариант 1

Добавить столбцы для AddressID в таблицы Customer и Vendor. Это просто не кажется мне чистым решением.

Customer     Vendor         Address
--------     ---------      ---------
CustomerID   VendorID       AddressID
AddressID1   AddressID1     Street
AddressID2   AddressID2     City...

Вариант 2

Переместите внешний ключ в таблицу Address. Для Клиента будет заполнено Address.CustomerID. Для Продавца будет заполнено Address.VendorID. Мне это тоже не нравится - мне не нужно изменять адресную таблицу каждый раз, когда я хочу использовать ее для другого объекта.

Customer     Vendor         Address
--------     ---------      ---------
CustomerID   VendorID       AddressID
                            CustomerID
                            VendorID

Вариант 3

Я также видел это - только 1 столбец внешнего ключа в таблице адресов с другим столбцом, чтобы определить, к какой таблице внешнего ключа принадлежит адрес. Мне не нравится этот, потому что он требует, чтобы все таблицы внешнего ключа имели одинаковый тип идентификатора. Это также кажется грязным, когда вы начинаете кодировать против него.

Customer     Vendor         Address     
--------     ---------      ---------
CustomerID   VendorID       AddressID
                            FKTable
                            FKID

Итак, я просто слишком разборчив или есть что-то, о чем я не подумала?

Ответы [ 4 ]

8 голосов
/ 20 мая 2010

Я бы сказал, что недостающий фрагмент головоломки - это отношение "есть", которое часто упускается из виду при моделировании данных; это отличается от привычных отношений. Отношение «является» похоже на отношение наследования в объектно-ориентированном дизайне. Для моделирования вам понадобится базовая таблица, которая представляет общие атрибуты поставщиков и клиентов. Например, мы можем назвать базовую таблицу «Организации»:

Organizations       Vendors               Customers
--------------      ---------------------  ---------------------
OrganizationID(PK)  OrganizationID(FK/PK)  OrganizationID(FK/PK)
AddressID1(FK)
AddressID2(FK)

В этом примере Поставщик "является" организацией, а Заказчик "является" организацией, в то время как организация "имеет" адрес. Таблицы «Организации», «Поставщики» и «Клиенты» имеют общий ключ и последовательность общих ключей, обеспечиваемую ссылочной целостностью.

6 голосов
/ 19 мая 2010

Я думаю, что из трех вариантов, которые вы предоставили, я бы больше всего склонялся к варианту 1. Обычно у клиента или поставщика не будет больше, чем несколько разных адресов, но если они это сделают, возможно, решение ниже будет работать лучше для вас. Я бы не стал использовать вариант 2, потому что, вероятно, не имеет смысла связывать Адрес одновременно с Заказчиком и Продавцом. Я знаю, что вы, вероятно, устанавливаете только один из этих идентификаторов за раз, но модель может сбивать с толку, и вам может понадобиться добавить специальную логику, чтобы убедиться, что только CustomerID или VendorID установлен для любой данной записи. Я определенно не буду делать вариант 3, потому что вы не можете сделать FKID настоящим FK. Если вы хотите, чтобы столбец ссылался более чем на одну таблицу, вы не сможете использовать ограничение FK в базе данных для его применения. Кроме того, если вы планируете использовать ORM для взаимодействия с базой данных в коде, у них, как правило, возникают проблемы с «поддельными» внешними ключами, которые ссылаются на несколько таблиц в зависимости от отдельного столбца «дискриминатора».

Если вы хотите действительно открытое решение, вы можете создать отношения «многие ко многим» между Customer и Address и Vendor и Address.

Customer
--------
CustomerID (PK)

Vendor
------
VendorID (PK)

Address
-------
AddressID (PK)

CustomerAddress
---------------
CustomerID (FK/PK)
AddressID (FK/PK)

VendorAddress
-------------
VendorID (FK/PK)
AddressID (FK/PK)
1 голос
/ 07 августа 2016

Как насчет четырех таблиц, одна из которых выступает в качестве шлюза к адресам? Таким образом, вы бы

Customer
    customerId (PK)
    addressBookId (FK to AddressBook)

Vendor
    vendorId (PK)
    addressBokId (FK to AddressBook)

AddressBook
    addressBookId (PK)

Address
    addressId (PK)
    addressBookId (FK to AddressBook)
0 голосов
/ 19 мая 2010

Можете ли вы изменить дизайн таблицы, чтобы иметь следующие поля:

 Address_Type  (a flag to say that this is a customer, or a vendor)
 ID            (a common ID for both customer and vendor and depending on the flag you know what ID it is)
 Address       (Data of address itself)

или вы можете иметь две таблицы:

  • Таблица адресов, где нет ссылок на типы адресов. т.е. иметь оба
    • идентификатор объекта (ключ)
    • Адрес
  • таблица типов адресов, где она будет указывать на запись и иметь флаг вне таблицы, чтобы иметь:
    • идентификатор объекта (от FK до идентификатора объекта в приведенной выше таблице)
    • тип объекта (клиент или поставщик)
...