談Apache OFbiz 會員模組表結構設計,apacheofbiz

來源:互聯網
上載者:User

談Apache OFbiz 會員模組表結構設計,apacheofbiz

資料庫表的結構設計可謂是ofbiz除技術架構之外,另一個非常值得學習的方向。這篇文章我們來談談ofbiz對電子商務會員表的設計。

PARTY

ofbiz對人、團體進行了抽象,稱之為party,翻譯為中文稱之為“會員”(但我覺得拋開領域,如果你也有相關的設計需求,在其他領域可能稱之為團體更合適)。會員在ofbiz被設計為一個抽象的概念(對應到物件導向設計中,你可以稱其為一個基類),它有兩個具體的延伸(繼承者):分別是PERSON以及PARTY_GROUP。資料庫的E-R圖:


這裡PERSON,PARTY_GROUP分別表示“個人會員”、“組織會員”。Party只是一種抽象,它定義了可以被抽象為“會員”的對象所具有的基本特徵。但 “個人”以及“組織”會員卻具備比 “基本會員”更多的特徵,所以此處從Party延伸出兩張表來儲存這些額外的特徵資訊它們的主鍵都是PARTY表的PARTY_ID。

PARTY_TYPE

partyType定義了party的類型約束。E-R圖如下:


可以看到,PARTY_TYPE是擁有層級關係的(它的一個屬性PARENT_TYPE_ID自關聯了PARTY_TYPE的主鍵:PARTY_TYPE_ID,下面如果看到E-R圖上有自關聯到本身的,都表示這種關係,不再敖述)。

ofbiz提供的初始資料中有如下幾種party type:


構建成層級關係如所示:


上面展示的兩張表:PERSON、PARTY_GROUP也是其中的兩個partyType,並且這些partyType都可以獨立擴充的,PERSON、PARTY_GROUP也是僅有的兩個擴充。這也是上面表結構中這兩個記錄的HAS_TABLE值為Y的原因。

PARTY_ROLE

就跟社會的“角色分工”一樣,一個會員在系統中也必定會擁有屬於自己的角色。而PARTY_ROLE表就是用於關聯會員與角色類型的關係表,很明顯會員與角色類型是多對多的關係(這裡需要提及的是:ofbiz中只有角色類型,沒有角色,或者更準確點說,角色類型包含了角色)。


PARTY_RELATIONSHIP

上面我們看到的會員是一類“抽象”的實體。不管它表示的是個人,還是組織,它總是會跟其他會員發生關係,就好像一個人不可能脫離社會而孤立得存在著,他必然有自己的社會角色,並跟社會的其他“團體”產生聯絡。這在ofbiz中被抽象為“partyRelationship”。我們來看它是如果表達“關係”這個語義的:


當你把這些所有的欄位連起來,它幾乎能涵蓋所有的“會員關係”(要知道,有時會員關係會非常複雜,一個會員有時會存在於多個系統中)。

我們再回過頭來,看PARTY_RELATIONSHIP的表結構設計:


可以看到前五個鍵形成了聯合主鍵,其中前四個都是形如XXX_FROM,XXX_TO的ID標識。表示從“FROM”方往“TO”方建立關係。其中PARTY_ID_FROM與ROLE_TYPE_ID_FROM是“源”方;PARTY_ID_TO與ROLE_TYPE_ID_TO是“目標”方。

從上面圖中也可以看到,每個關係都帶有兩個DATETIME欄位,分別表示:開始日期,到期日。這說明關係是有“時段”這個屬性的。當然,如果沒有到期日,可以看做是“永久”的。因此為了防止關係過了生效時段無法再次建立關係(因為主鍵不允許重複),所以選擇了聯合“FROM_DATE”作為聯合主鍵(後面如果再次建立相同的關係時,只要FROM_DATE不一樣,就視為一條新記錄)。

這裡有必要說明一下,在ofbiz的資料庫設計中,大量採用了“時段”這個屬性來標識記錄的有效性。這樣的設計與邏輯刪除相比的好處是:它除了減少了刪除時因為外鍵約束等連帶關係導致的錯誤,還可以直接充當“記錄”的作用,省去了對曆史表的維護,當然它的缺點就是:表中的記錄會比其他的設計多得多。

當然,From跟To只是為了標識兩者建立了關係,卻並未說明它們到底存在怎樣的關係,就好像——我跟你是朋友。這句話可以拆分為三部分:FROM方:我,TO方:你,關係是:朋友。上表中用一個欄位表示了關係:PARTY_RELATIONSHIP_TYPE_ID(這隻是一個外鍵,關聯著表PARTY_RELATIONSHIP_TYPE)。

在介面上建立一個關係(此處是從外部到自己的一個關係):


PARTY_RELATIONSHIP_TYPE

該資料表條件約束了關係的類型。比如:僱傭者、朋友、父、子、管理者,E-R圖:


可以看出,會員關聯類型也擁有層次關係。表中還有兩個特別的欄位:

  • ROLE_TYPE_ID_VALID_FROM
  • ROLE_TYPE_ID_VALID_TO
它們用於約束這個關係的建立雙方的角色。也就是說,不是任意的兩個角色之間一定可以建立起某個特定的會員關係。當然這兩個欄位通常都為空白,表示不對此加以限制。
對每個關聯類型,都可以擴充以獨立實現關係(被擴充後關聯類型記錄的欄位HAS_TABLE被標識為Y,否則預設為N),在ofbiz的初始化資料中,唯一被擴充的關聯類型是:EMPLOYMENT。我們來看看EMPLOYMENT關係表的實現:

可以看到,它跟之前的PARTY_RELATIONSHIP的主鍵實現方式一樣。因此可以把它看做是:PARTY_RELATIONSHIP_TYPE_ID為EMPLOYMENT的PARTY_RELATIONSHIP的特殊實現。
在介面上建立一個關聯類型:

PARTY_CLASSIFICATION_TYPE為了便於管理,ofbiz對會員按各種維度進行分類,常見的分類的類型有:年度營收、價值等級、產業、僱員數量等;
PARTY_CLASSIFICATION_GROUP會員並不會直接跟分類的類型產生關係,而是跟一個或多個分類組產生關聯關係。而分類組受分類類型約束。
建立一個分類組:

PARTY_CLASSIFICATION會員的分類相關表的關係圖:

從表的關聯關係可以看出,會員分類跟分類組是多對多的關係,並且分類具有時效性。因此聯合FROM_DATE作外鍵。
將會員劃歸入一個會員分類:

CONTENT_MECH從這張表開始,我們來看會員的連絡方式相關的表結構設計,這也是一部分非常棒的設計。
這張表格儲存體了連絡方式基本資料。它引用了另一張表:CONTENT_MECH_TYPE作為外鍵,來表示該連絡方式的類型(通常的連絡方式類型有電話、郵箱、網址等)。
CONTENT_MECH_TYPE
可以看到連絡方式類型,也是具有層級結構(父子關係)的。
當我們想建立一個連絡方式時,首先必須先指定想建立的連絡方式的類型:

PARTY_CONTACT_MECH毫無疑問,地址資訊只有跟會員聯絡起來,才能表示會員的地址。而會員跟地址是多對多的關係,理解這個關係時需要注意的是會員可以是任何團體、組織或者個人。那這裡可能就會存在兩個不同的會員擁有同一個連絡方式的可能,比如:一個員工會員與一個該員工所屬的公司會員,它們可以都存在同一個連絡方式:公司的郵寄地址。當然一個會員擁有多個連絡方式,這是很容易理解的。所以會員標識跟連絡方式標識之間是多對多的關係,並且跟前面的設計模式相似——連絡方式也有時效性,比如換電話號碼,換工作導致連絡方式變化等,所以聯合FROM_DATE作為聯合主鍵:

當我們選擇連絡方式類型為電話號碼時,會出現如下的表單填寫:

如果你建立一個連絡方式的類型為電話號碼,那麼電話號碼儲存在何處?此處又跟前面談到的HAS_TABLE欄位有關(CONTACT_MECH_TYPE中也存在這個欄位)。正常情況下,連絡方式關聯著連絡方式類型,普通的連絡方式的具體資訊儲存在CONTACT_MECH的INFO_STRING屬性中。但有些聯絡資訊不是單純的像郵箱這樣只是一個字串,比如像電話號碼、郵遞區號…它們都有具體的格式表示。所以這些特例用INFO_STRING這一個屬性儲存區也不方便,因此可以獨立擴充該CONTACT_MECH_TYPE(將其HAS_TABLE欄位設定為Y,這樣查詢該CONTACT_MECH資訊的時候,就不採用INFO_STRING欄位,而是採用擴充表中格式化的連絡方式)。
CONTACT_MECH_PURPOSE_TYPE當我們點擊上面介面的儲存按鈕之後,會更進一步得擴充聯絡資訊:

在ofbiz中還存在一個稱之為“聯絡目的”的東西,它是什麼意思?

看到選項我們就會明白,說白了一個人的地址簿或者電話簿中的連絡方式可能有很多。它們沒有主次之分,只有目的不同。
PARTY_CONTACT_MECH_PURPOSE上面談到了聯絡目的,那麼很自然它需要跟會員具體的某條聯絡資訊關聯起來才能稱之為:某個會員為了某種聯絡目的儲存了一個“連絡方式”記錄。

這裡需要注意的是,它並沒有跟PARTY_CONTACT_MECH產生直接關聯(沒有外鍵關係),而是把PARTY_CONTACT_MECH的三個主鍵照搬過來,聯合CONTACT_MECH_PURPOSE_TYPE_ID形成四個組合主鍵,這是因為PARTY_CONTACT_MECH的聯合主鍵機制無法被其他表當做外鍵引用。因此,可以將PARTY_CONTACT_MECH_PURPOSE看作聯絡資訊模組的彙總。這個怎麼來理解?其實一個地址可以看成:某個會員(PARTY_ID),出於某種目的(CONTACT_MECH_PURPOSE_TYPE_ID),在某段時間內(FROM_DATE),儲存了某個連絡方式(CONTACT_MECH_ID)。這種連絡方式的設計非常有彈性,因此在大部分情況下,這種抽象效能夠涵蓋大部分應用情境。
CONTENT_TYPE會員內容的設計跟連絡方式類似。會員可以有一個類似檔案空間在伺服器上,可以供其儲存文檔、圖片之類的東西。CONTENT_TYPE限定了會員可以儲存的內容類型:

CONTENT該表是它的具體儲存內容的地方,當然並不是唯一的,如果CONTENT_TYPE有一條記錄的HAS_TABLE值為Y,則那個記錄對應的表也用於儲存內容。內容表裡的欄位非常多,就不了。
跟之前的聯絡資訊類似,會員可以有多個內容,一個內容也可能從屬於多個會員。因為會員是個抽象的概念,對應到實體上可能會有重合,所以需要一個“目的”來修飾會員內容,它就是——PARTY_CONTENT_TYPE。
PARTY_CONTENT_TYPE用於修飾會員內容的用途,當然這裡它的表名叫type,事實上從資料記錄來看,來時充當了目的的作用。

內容還跟其他一些表有關聯(主要是被參考關聯性,比如:CONTENT_ROLE等),此處因為跟本文主題沒太大關係,所以不再敖述。
總結更高的抽象層級ofbiz party模組的設計,正如它所應用的情境:非常適用於電子商務系統會員資訊相關的設計。當然ofbiz中其他相關的多個系統也同樣應用了這些表結構,這也意味著它有適用於一般行業、系統的通用性,這得益於這種設計的抽象層級比較高。它可以描述任何的組織、個體、他們的地址資訊、他們之間的關係。特別是對會員“relationship”表的設計非常類似於《分析模式》中談到的責任模式:

因此,如果你面臨組織圖比較複雜的業務情境時,比如群組、連絡人、個人、公司都可以成為系統的使用者,又或者一個非常大的跨國公司,擁有:總部、地區銷售辦公室、辦事處、分公司等各種組織形式時,這種設計就會派上用場。
資料庫表的繼承關係從PARTY、PARTY_TYPE、PARTY_GROUP、PERSON這幾張表我們可以學習到資料庫表的“繼承”設計。
時效性設計不是真刪除、也不是邏輯刪除、而是失效(FROM_DATE, THUR_DATE)。這種方式可以代替“操作-操作曆史”的多表設計,轉而合并為獨立的一張表。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.