天天看點

談Apache OFbiz 會員子產品表結構設計

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

PARTY

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

談Apache OFbiz 會員子產品表結構設計

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

PARTY_TYPE

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

談Apache OFbiz 會員子產品表結構設計

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

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

談Apache OFbiz 會員子產品表結構設計

建構成層級關系如下圖所示:

談Apache OFbiz 會員子產品表結構設計

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

PARTY_ROLE

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

談Apache OFbiz 會員子產品表結構設計

PARTY_RELATIONSHIP

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

談Apache OFbiz 會員子產品表結構設計

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

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

談Apache OFbiz 會員子產品表結構設計

可以看到前五個鍵形成了聯合主鍵,其中前四個都是形如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)。

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

談Apache OFbiz 會員子產品表結構設計

PARTY_RELATIONSHIP_TYPE

該表限制了關系的類型。比如:雇傭者、朋友、父、子、管理者,E-R圖:

談Apache OFbiz 會員子產品表結構設計

從圖中可以看出,會員關系類型也擁有層次關系。表中還有兩個特别的字段:

  • ROLE_TYPE_ID_VALID_FROM
  • ROLE_TYPE_ID_VALID_TO

它們用于限制這個關系的建立雙方的角色。也就是說,不是任意的兩個角色之間一定可以建立起某個特定的會員關系。當然這兩個字段通常都為空,表示不對此加以限制。

對每個關系類型,都可以擴充以獨立實作關系(被擴充後關系類型記錄的字段HAS_TABLE被辨別為Y,否則預設為N),在ofbiz的初始化資料中,唯一被擴充的關系類型是:EMPLOYMENT。我們來看看EMPLOYMENT關系表的實作:

談Apache OFbiz 會員子產品表結構設計

可以看到,它跟之前的PARTY_RELATIONSHIP的主鍵實作方式一樣。是以可以把它看做是:PARTY_RELATIONSHIP_TYPE_ID為EMPLOYMENT的PARTY_RELATIONSHIP的特殊實作。

在界面上建立一個關系類型:

談Apache OFbiz 會員子產品表結構設計

PARTY_CLASSIFICATION_TYPE

為了便于管理,ofbiz對會員按各種次元進行分類,常見的分類的類型有:年收入、價值等級、産業、雇員數量等;

PARTY_CLASSIFICATION_GROUP

會員并不會直接跟分類的類型産生關系,而是跟一個或多個分類組産生關聯關系。而分類組受分類類型限制。

建立一個分類組:

談Apache OFbiz 會員子產品表結構設計

PARTY_CLASSIFICATION

會員的分類相關表的關系圖:

談Apache OFbiz 會員子產品表結構設計

從表的關聯關系可以看出,會員分類跟分類組是多對多的關系,并且分類具有時效性。是以聯合FROM_DATE作外鍵。

将會員劃歸入一個會員分類:

談Apache OFbiz 會員子產品表結構設計

CONTENT_MECH

從這張表開始,我們來看會員的聯系方式相關的表結構設計,這也是一部分非常棒的設計。

談Apache OFbiz 會員子產品表結構設計

這張表存儲了聯系方式基本資訊。它引用了另一張表:CONTENT_MECH_TYPE作為外鍵,來表示該聯系方式的類型(通常的聯系方式類型有電話、郵箱、網址等)。

CONTENT_MECH_TYPE

談Apache OFbiz 會員子產品表結構設計

可以看到聯系方式類型,也是具有層級結構(父子關系)的。

當我們想建立一個聯系方式時,首先必須先指定想建立的聯系方式的類型:

談Apache OFbiz 會員子產品表結構設計

PARTY_CONTACT_MECH

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

談Apache OFbiz 會員子產品表結構設計

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

談Apache OFbiz 會員子產品表結構設計

如果你建立一個聯系方式的類型為電話号碼,那麼電話号碼存儲在何處?此處又跟前面談到的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

當我們點選上面界面的儲存按鈕之後,會更進一步得擴充聯系資訊:

談Apache OFbiz 會員子產品表結構設計

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

談Apache OFbiz 會員子產品表結構設計

看到選項我們就會明白,說白了一個人的位址簿或者電話簿中的聯系方式可能有很多。它們沒有主次之分,隻有目的不同。

PARTY_CONTACT_MECH_PURPOSE

上面談到了聯系目的,那麼很自然它需要跟會員具體的某條聯系資訊關聯起來才能稱之為:某個會員為了某種聯系目的存儲了一個“聯系方式”記錄。

談Apache OFbiz 會員子產品表結構設計

這裡需要注意的是,它并沒有跟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限定了會員可以存儲的内容類型:

談Apache OFbiz 會員子產品表結構設計

CONTENT

該表是它的具體存儲内容的地方,當然并不是唯一的,如果CONTENT_TYPE有一條記錄的HAS_TABLE值為Y,則那個記錄對應的表也用于存儲内容。内容表裡的字段非常多,就不截圖了。

跟之前的聯系資訊類似,會員可以有多個内容,一個内容也可能從屬于多個會員。因為會員是個抽象的概念,對應到實體上可能會有重合,是以需要一個“目的”來修飾會員内容,它就是——PARTY_CONTENT_TYPE。

PARTY_CONTENT_TYPE

用于修飾會員内容的用途,當然這裡它的表名叫type,事實上從資料記錄來看,來時充當了目的的作用。

談Apache OFbiz 會員子產品表結構設計

内容還跟其他一些表有關聯(主要是被引用關系,比如:CONTENT_ROLE等),此處因為跟本文主題沒太大關系,是以不再敖述。

總結

更高的抽象級别

ofbiz party子產品的設計,正如它所應用的場景:非常适用于電子商務系統會員資訊相關的設計。當然ofbiz中其他相關的多個系統也同樣應用了這些表結構,這也意味着它有适用于一般行業、系統的通用性,這得益于這種設計的抽象級别比較高。它可以描述任何的組織、個體、他們的位址資訊、他們之間的關系。特别是對會員“relationship”表的設計非常類似于《分析模式》中談到的責任模式:

談Apache OFbiz 會員子產品表結構設計

是以,如果你面臨組織結構比較複雜的業務場景時,比如群組、聯系人、個人、公司都可以成為系統的使用者,又或者一個非常大的跨國公司,擁有:總部、區域銷售辦公室、辦事處、分公司等各種組織形式時,這種設計就會派上用場。

資料庫表的繼承關系

從PARTY、PARTY_TYPE、PARTY_GROUP、PERSON這幾張表我們可以學習到資料庫表的“繼承”設計。

時效性設計

不是真删除、也不是邏輯删除、而是失效(FROM_DATE, THUR_DATE)。這種方式可以代替“操作-操作曆史”的多表設計,轉而合并為獨立的一張表。

原文位址:https://blog.csdn.net/yanghua_kobe/article/details/41788949