Вы можете сделать это любым способом: большая гудящая таблица billingoptions
, в которой есть поля, охватывающие все типы, с нулевыми значениями для полей, которые не относятся к данному типу, или куча дочерних таблиц, которые «стартуют» от родителя. billingoptions
стол. Оба имеют свои преимущества и недостатки.
Для большого гудящего стола,
- Удобно, что на все данные можно легко ссылаться в одной таблице.
- Эффективно отслеживание зависимостей внешнего ключа и выполнение обновлений или вставок.
- НО вам необходимо изменить структуру таблицы, чтобы добавить новые варианты выставления счетов в будущем, и существует вероятность того, что будут сохранены недопустимые комбинации данных (например, в одной и той же записи будут установлены как тип кредитной карты, так и флаг наложенного платежа).
Для маленьких детских столов,
- Хорошо, что данные разделены и точно отражают структуру объекта вашей программы.
- Приятно, что вы можете добавлять новые способы оплаты или изменять существующие, не беспокоясь о том, что это повлияет на другие.
- Отношения ОЧЕНЬ явные. Вы не можете случайно связать депозит с другим депозитом, так как внешний ключ потребует, чтобы он был связан с утверждением.
- НО вы в конечном итоге вводите в дизайн множество таблиц, которые требуют большого количества JOIN, могут быть болезненными для навигации и не так эффективны, когда дело доходит до вставок и обновлений.
На работе мы остановились на маленьких детских столиках. Это выглядит примерно так:
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
и т. д.). Абстракция за последние полтора года довольно хорошо работала в этих разрозненных методах, хотя иногда графический интерфейс будет отображать для пользователя разные формулировки (например, он будет говорить «Авторизовать» и «Оплата» вместо «Утвердить» и «Депозит» для платежей по кредитным картам, а экран для ввода наличных выполняет этап «Утвердить/Депозит» одним махом.)
Надеюсь, это имеет смысл. Похоже, вы на самом деле не храните информацию о платежах, но полезно подумать о том, где эти вещи могут оказаться.
person
Nicholas Piasecki
schedule
23.11.2008