ofbiz中,party的电话、地址等联系方式设计得非常巧妙,让我们来仔细分析一下。
有一个叫做CONTACT_MECH的表,这张表我们把它称作联系方式表,一个电话号码、一个通讯地址、一个电子邮件,都分别会在这张表里找到对应的一条记录。然后通过PARTY_CONTACT_MECH表与PARTY进行多对多关联,也就是一个PARTY可以对应多个联系方式,同样一个联系方式也可以对应多个PARTY(比如家庭成员共用一个电话号码)。
在PARTY_CONTACT_MECH里,我们又发现了FROM_DATE和THRU_DATE两个字段。我们当然可以理解,每个联系方式都会有有效期间(从FROM_DATE到THRU_DATE),这样的设计使得我们不必为PARTY的联系方式烦恼了。比如,某个用户的电话号码改变了,我们只需在原先的PARTY_CONTACT_MECH记录里的THRU_DATE设为今天,然后新增一条记录代表用户新的电话号码。这样的设计,保留了老的电话号码,使得系统运维人员总是能够找到历史的记录。
在CONTACT_MECH表里,有两个字段:CONTACT_MECH_TYPE_ID和INFO_STRING。我们先来看CONTACT_MECH_TYPE_ID,该字段是个外键指向CONTACT_MECH_TYPE。如果我们在初始化ofbiz的时候导入了初始数据,就会发现CONTACT_MECH_TYPE里存放的是“EMAIL_ADDRESS”、“POSTAL_ADDRESS”、“TELECOM_NUMBER”等联系方式的类型。这里有人会问,怎么没有MOBILE_NUMBER(手机号码)?在ofbiz中,手机的联系方式类型也是“TELECOM_NUMBER”。那如何表达手机呢?这时需要引入另外一张表,CONTACT_MECH_PURPOSE_TYPE。在初始化数据里,我们发现许多例如“PHONE_HOME”、“SHIPPING_LOCATION”、“PHONE_MOBILE”等代表联系目的的数据。手机是作为一种联系目的在CONTACT_MECH_PURPOSE_TYPE表中定义了(也就是“PHONE_MOBILE”这条数据),并通过CONTACT_MECH_TYPE_PURPOSE表(注意不是CONTACT_MECH_PURPOSE_TYPE)与CONTACT_MECH_TYPE_ID进行了多对多的关联。CONTACT_MECH_TYPE_PURPOSE也就定义了哪些联系方式的类型可以有哪些联系目的。
在CONTACT_MECH里,有个字段叫INFO_STRING,如果这个CONTACT_MECH代表的是email,则INFO_STRING里的内容就是email,不过如果这个CONTACT_MECH代表的是电话号码或地址,那哪里存放区号、城市、邮编等内容呢?显然,ofbiz是不会把这些信息一股脑儿都弄成字符串存放到INFO_STRING里,这样的话,就必须有另外两张表:TELECOM_NUMBER(存放电话号码)和POSTAL_ADDRESS(存放地址),这两张表各有外键指向CONTACT_MECH。
到这里,我们已经把有关PARTY的联系方式介绍得差不多了,基本概念都已经在了。但是还有一张表,或许是最为关键的一张表,PARTY_CONTACT_MECH_PURPOSE。这张表里有主要是三个字段,都是外键:PARTY_ID(指向PARTY的外键)、CONTACT_MECH_ID(指向CONTACT_MECH的外键)、CONTACT_MECH_PURPOSE_TYPE_ID(指向CONTACT_MECH_PURPOSE_TYPE的外键)。这三个外键的组合,唯一指明了某个PARTY的某个联系方式(CONTACT_MECH)是做什么用的(CONTACT_MECH_PURPOSE_TYPE)。
不过这个PARTY_CONTACT_MECH_PURPOSE和PARTY_CONTACT_MECH感觉上是重合的,PARTY_CONTACT_MECH_PURPOSE已经包含了PARTY_CONTACT_MECH的所有信息,之所以还要有PARTY_CONTACT_MECH,可能也是为了概念上以及使用上的方便,不过这个也增加了维护方面的成本。