Вы можете сделать это любым способом: большая сигнальная таблица billingoptions
, которая имеет поля, охватывающие все типы, с NULL для полей, которые не относятся к данному типу, или набор детских таблиц, которые "помечаются" выкл "родительской billingoptions
таблицы. Оба имеют свои преимущества и недостатки.
Для большого сигнального стола
- Приятно, что на все данные можно легко ссылаться в одной таблице.
- Эффективно отслеживание зависимостей внешнего ключа и выполнение обновлений или вставок.
- НО вам нужно изменить структуру таблицы, чтобы добавить новые возможности выставления счетов в будущем, и есть вероятность того, что будут сохранены недопустимые комбинации данных (например, тип кредитной карты и флаг ХПК устанавливаются в одной и той же записи). ).
Для маленьких детских столиков
- Приятно, что данные разбиты на разделы и близко отражают структуру объектов вашей программы.
- Приятно, что вы можете добавлять новые способы оплаты или изменять существующие, не беспокоясь о влиянии на другие.
- Отношения ОЧЕНЬ явны. Вы не можете случайно связать депозит с другим депозитом, поскольку внешний ключ требует, чтобы он был связан с одобрением.
- НО вы в конечном итоге вводите в дизайн множество таблиц, которые требуют большого количества соединений, могут быть трудны для навигации и не столь эффективны, когда дело доходит до вставок и обновлений.
На работе мы закончили тем, что ходили с маленькими детскими столиками. Это выглядит примерно так:
Table Orders:
--> OrderId PK
--> (Lots of Other Fields)
Table Payments:
--> PaymentId PK
--> OrderId (FK) [There may be more than one payment per order]
--> PaymentType [Restricted field contains values like
'PAYPAL' or 'CREDIT', you use this to know which
baby table to look up that can contain additional
information]
Table PaymentsPayPal:
--> PaymentPayPalId PK
--> PaymentId FK points to Table Payments
--> TransactionNo
--> (Other PayPal specific fields)
Table PaymentsCheck:
--> PaymentCheckId PK
--> PaymentId FK points to Table Payments
--> RoutingNo
--> (Other e-check specific fields)
+ other tables for remaining payment types....
Все типы платежей имеют три общие таблицы транзакций:
Table PaymentApprovals:
--> PaymentApprovalId PK
--> PaymentId FK points to Table Payments
--> Status [Some flag meaning 'Succeeded', 'Failed', 'Reversed', etc]
--> ProcessorMessage [Something the service sent back, like '(M) CVV2 Matched']
--> Amount
--> (Other administrative fields)
Table PaymentDeposits:
--> PaymentDepositId PK
--> PaymentApprovalId FK points to Table PaymentApprovals
--> Status
--> ProcessorMessage
--> Amount
--> (Other administrative fields)
Table PaymentRefunds:
--> PaymentRefundId PK
--> PaymentDepositId FK points to Table PaymentDeposits
--> Status
--> ProcessorMessage
--> Amount
--> (Other administrative fields)
Все наши способы оплаты (Кредитная карта, PayPal, Google Checkout, Чек, Наличные, Кредит в магазине и Денежный перевод) абстрагированы для соответствия метафоре Утверждение -> Депозит -> Возврат, и пользовательский интерфейс вызывает те же методы на интерфейсах IPayment
и IPaymentProcessor
с различными реализациями (CybersourcePaymentProcessor
, PayPalPaymentProcessor
и т. д.). За последние полтора года абстракция работала довольно хорошо для этих разрозненных методов, хотя иногда графический интерфейс пользователя отображает различные словесные выражения для пользователя (например, вместо «Одобрить» и «Утвердить» и «Разрешить»). «Депозит» для платежей по кредитным картам, и экран для ввода наличных выполняет шаг Одобрить / Депозит одним махом.)
Надеюсь, это имеет смысл. Похоже, что вы на самом деле не храните информацию об оплате, но полезно подумать о том, где все это может закончиться.