我有一个创建订单的系统,该订单可以记入自家账户、发送货到付款 (COD) 或记入信用卡。我创建了下表:
订单
订单编号
billingoption_id
账单选项
billingoption_id
我不确定应该如何为计费数据构建下一个表。我应该为每种类型的计费选项(即 COD、信用卡和家庭账户)建立一个单独的表吗?那么我是否会在 Orders 表上有另一个外键列来引用账单数据的记录?
最佳答案
您可以采用任何一种方式:一个巨大的 billingoptions
表,其中包含包含所有类型的字段,对于不适用于给定类型的字段为 NULL,或者一堆从父 billingoptions
表“开始”的婴儿表。两者各有优缺点。
对于大喇叭表,
- 很高兴所有数据都可以在一个表中轻松引用。
- 跟踪外键依赖关系并执行更新或插入是有效的。
- 但是您需要更改表结构以在将来添加新的计费选项,并且可能会存储无效的数据组合(例如,信用卡类型和 COD 标志都设置在同一记录中).
对于小婴儿 table ,
- 很高兴数据被分区并密切反射(reflect)了程序的对象结构。
- 很高兴您可以添加新的支付选项或更改现有的支付选项,而不必担心影响其他选项。
- 关系非常明确。您不会意外地将一笔存款与另一笔存款关联起来,因为外键需要将其与批准关联起来。
- 但您最终会在设计中引入大量表格,这需要大量 JOIN,导航起来可能很痛苦,并且在插入和更新方面效率不高。
在工作中,我们最终选择了小型婴儿 table 。它看起来像这样:
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、支票、现金、商店信用和汇票)都被抽象出来以适应这个批准 --> 存款 --> 退款隐喻,UI 调用IPayment
和 IPaymentProcessor
接口(interface)上的相同方法与不同的实现(CybersourcePaymentProcessor
、PayPalPaymentProcessor
等)。在过去一年半的时间里,抽象在这些不同的方法中运行良好,尽管有时 GUI 会向用户显示不同的措辞(例如,它会说“授权”和“收费”而不是“批准”和信用卡支付的“存款”,输入现金的屏幕一口气执行批准/存款步骤。)
希望这是有道理的。听起来好像您实际上并没有存储付款信息,但考虑一下这些东西最终会放在哪里是很有用的。
关于design-patterns - 我可以使用什么数据库模式来保存不同类型的账单数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/312006/