3

對於用戶可以是memberadmin的系統,具有member角色的用戶必須使用定期訂閱進行付費,或者獲得免費訪問權限。訂閱管理邏輯

我目前的做法:

  • 用戶有一個user數據庫表。
  • A subscription表格包含用戶的記錄(如果他們有訂閱)。
  • A subscription_event表記錄了每個結算或付款失敗。我可以查詢這一點,看看最後的事件是否確實是成功的支付。

但是如何記錄用戶是否獲得「免費」訪問權限?

  • 有另一張表complimentary_subscription與用戶ID作爲外鍵?
  • subscription中爲他們記錄一個特殊的「訂閱」?
  • 或者在is_complimentarycomplimentary_expires_date這樣的列中爲其用戶行添加另一列?
  • 向用戶行添加更一般的expires列?
+0

Hi @eoinoc。用戶獲得「免費訪問」訂閱意味着什麼?什麼屬性與正規訂閱有共同之處,以及歸因對於「免費訪問」是必不可少的? – nick2083 2012-01-01 04:58:15

+0

@ nick2083這意味着我們可以爲他們提供會員級別的系統訪問權限,但是他們不需要付費,不像普通會員必須按月訂購。 – eoinoc 2012-01-01 10:10:39

回答

5

問題審查

正如@leanne說,你造型Subscription,其專長是,比方說,MonthlySubscriptionComplimentarySubscription(給他們這個答案的名稱)。

你知道,訂閱可能過期:

  • 對於MonthlySubscription,這種情況發生在用戶沒有支付當月的訂閱
  • 對於ComplimentarySubscription,到期日期分配時,它的分配用戶

正如你可以看到一個ExpirationDate任何Subscription的本質屬性,但你保存它的方式是在每種情況下的不同。如果第一種情況你必須根據最後一個事件來計算它,在後者中你可以直接檢索它。

在數據庫

因此,與繼承處理,繪製該樣本模型數據庫模式,你可以在Martin Fowler的Patterns of Enterprise Application Architecture本書中描述的Class Table Inheritance模式去。這是它的意圖:

「表示類的繼承層次結構,每個類有一個表」。

基本上,您將擁有一個表格,其中的類別之間共有的屬性共享,並且您將在單獨的表格中存儲特定於每個類別的屬性。

牢記這一點,讓我們回顧一下你提出的方案:

  • 有另一個表complimentary_subscription與用戶ID爲外鍵?

具有儲存ComplimentarySubscription具體細節一個單獨的表聽起來不錯,但如果你不涉及這一塊與subscription表,你可以同時具有MonthlySubscriptionComplimentarySubscription的用戶結束。它的外鍵應該指向subscription表,該表可以告訴您用戶是否有訂閱(並且您必須強制每個用戶最多一次訂閱)。

  • 記錄在subscription一個特殊的 「訂閱」 又在哪裏?

是的,你必須記錄一個用戶訂閱每月或免費。但是,如果您正在考慮像記錄一個數量爲零的特殊訂閱這樣的東西,那麼您正在尋找一種與您當前的設計相匹配的解決方案,而不是爲它尋找合適的模型(它可能並非如此)。

  • 或添加其他列到他們的用戶排像is_complimentarycomplimentary_expires_date列?

我個人不喜歡這一個,因爲你把信息放在不屬於它的地方。考慮到這一點,您將在哪裏存儲免費訂閱的截止日期(請記住,對於每月的訂閱日期,您正在計算它,而不是存儲到期日期)?似乎所有這些信息都爲自己的「家」而哭泣。 另外,如果以後您需要添加一個新類型的訂閱,表格將開始混亂。

  • 添加一個更一般的expires列給用戶的行?

如果你這樣做,你必須每個subscription_event得到改變的時間來處理數據同步(以包月的情況下)。通常我會盡量避免這種數據重複情況。

樣品溶液

我會做的添加新類型的訂閱時具有subscription表來存儲MonthlySubscriptonComplimentarySubscription之間共享信息,增加了type列鍵時會讓你看好的可擴展性區分一行與哪種訂閱有關。

然後,將特定於每個訂閱類型的詳細信息存儲在其自己的表中,引用父行subscription行。

用於檢索數據,你需要負責實例給出了subscriptiontype列值的正確類型的Subscription的對象。

您可以查看「企業應用程序體系結構模式」一書中的模式,以獲取有關如何定義type列值的進一步幫助,如何使用映射器對象執行實例化等。


01/03/2012更新:用於定義和處理type

這裏替代的澄清以下問題通過@enoinoc在評論中發佈更新:

特別是對於建議的type列,這是否可以是指向描述不同類型訂閱的Plans表的外鍵,例如前幾個月他們到期沒有付款。這聽起來合乎邏輯嗎?

Plans表中只要沒有靜態信息就不需要編輯就可以了。如果是這種情況,請不要過度概括您的解決方案,並將相關知識放入相應的Subscription子類中。

關於外鍵的方法,我能想到的一些缺點會這樣的:

  • 請記住,你的目標是要知道的Subscription至極子類在Plans表中每行的。如果你得到的只是一個外鍵值(比如說一個整數),那麼你必須編寫代碼來將該值映射到要使用的類。這意味着額外的工作:)
  • 如果你必須做不必要的額外工作,那很可能是因爲mainteinance會是一個痛苦:每當你添加一個新的計劃時,你都必須記住硬編碼它是外鍵值映射代碼。
  • 如果數據庫導出/導入操作不正確,外鍵可能會更改。如果發生這種情況,您的映射代碼將不再起作用,您將不得不再次部署您的軟件(或至少,更改過的部分)。

建議的解決方案

我會做的是投入type列在表Plans。該列將保存知道如何從特定行構建正確Subscription的類的名稱。

但是:爲什麼我們需要一個對象來構建每種類型的Subscription?因爲您將使用來自不同表格(subscription_eventcomplimentary_subscription)的信息來構建每種類型的對象,並且隔離並封裝該行爲總是很好的。

讓我們來看看Plans表可能看起來怎麼樣:

- 計劃表 -

ID |名稱|類型|其他色譜柱...

1 |每月| MonthlySubscriptionMapper |

2 |免費| ComplimentarySubscriptionMapper |

每個SubscriptionMapper可以定義一個方法Subscription MapFrom(Row aRow)從數據庫中取一排,並請您Subscription子類(在本例MonthlySubscriptionComplimentarySubscription)的正確實例。

最後得到的type列中指定的映射器的一個實例(不使用一個討厭的ifcase語句),你可以從該列的值取類名,並通過使用反射,創建一個類的實例。

+0

感謝您的意見,因爲它有助於我理解建議的示例解決方案背後的基本設計決策。特別是對於建議的「類型」列,這可能是一個指向「計劃」表的外鍵,它描述了不同類型的訂閱,例如他們在沒有付款的情況下到期前多少個月。這聽起來合乎邏輯嗎?我希望這不會顯示您對類表繼承所描述的內容的完全無知。 – eoinoc 2012-01-03 14:15:59

+0

Hi @eoinoc!一點都不,這是一個很好的問題,我很樂意提供幫助。我已更新我的帖子以回答該問題,請查看。 – nick2083 2012-01-03 22:55:38

1

免費訂閱是訂閱,但是。其到期付款金額和訂閱價格爲零。它的到期日期可以是任何您設定的免費訂閱與正規訂閱的截止日期。

如果您當前的設置不允許您基於這些因素成功查詢免費訂閱/用戶,則只需要一個單獨的列或表。

注意:我在此假設您目前將用戶與訂閱價格關聯。無論如何,如果訂閱價格在未來發生變化,或者您希望爲定期或促銷用戶啓用折扣,您也需要知道。