• 沒有找到結果。

中介軟體框架

3.4 框架實作設計

3.4.2 Object Relational Mapping

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

3.4.2 Object Relational Mapping

在多租戶 SaaS 的資料綱要設計選擇上,本研究是採用 Universal Table 資料架構,

但使用這套資料綱要有其難度。為了 SaaS 開發人員能更輕易快速的使用 Universal Table 資料架構,中介軟體框架將提供 ORM 的方式來存取 Universal Table 資料架構的資料,SaaS 開發人員不須自行撰寫符合 Universal Table 資料架 構的 SQL 指令以及維護相關的資料表。但由於 ORM 的概念發展已久,市面上 已有相當多的 ORM Framework,重新設計開發一套 ORM Framework 似乎事倍功 半,因此本研究將會評估一套市面上主流的 ORM Framework 撰寫其擴充套件 (PlugIn)來支援 Universal Table 資料架構。

目前市面上主流的 ORM Framework 主要有 Hibernate、iBATIS、DataNucleus 等等, 經過仔細評估過這幾個主流 ORM Framework 的架構與 SourceCode 後,

我們發現修改 DataNucleus 是最佳的選項。主要原因是 DataNucleus 為依據 OSGi 規格所開發而成,其核心(engine)部分與其他所希望實現的功能,皆能有效地的 分割,其各元件的相依性與耦合度低。也因為這樣的特性,DataNucleus 可以同 時支援 JPA(Java Persistence API)及 JDO(Java Data Object)這兩個 Java ORM 規 格。另外在資料來源方面,它也不像主流的 ORM Framework 只能支援關聯式資 料庫,其他各種不同的資料來源只要有人實現其 Plugin 便能使用,例如:excel、

xml、MongoDB 等等。DataNucleus 架構圖如下:

圖 3.4:DataNucleus 架構圖[28]。

從上圖可看出 DataNucleus AccessPlatoform 中分為三個區塊,分別是 API、

PersistenceEngine 及 Store Management。每個區塊中都是一個 Plugin,端看開發 人員想要使用那種規格,就直接利用該 Plugin,Plug 進 Engine 中。由此可看出 DataNucleus 的彈性所在,這也是選擇 DataNucleus 的進行修改的主要原因,避免 直接修改到其 Engine 的部分,只需針對其 DataStore RDBMS 的 Plugin 修改即可。

在中介軟體框架架構設計中 ORM 模組的任務為負責把查詢結果與領域物件對映 以及提供 ORM 的查詢語言,目前 DataNucleus 提供兩個 ORM 規格 JDO 及 JPA。

因為 JDO 規格可支援不同的資料來源,從 DataNucleus 的參考文件[27]中也發現 其是較為偏好 JDO 規格,本研究將先支援 JDO 的部分,修改 DataStore RDBMS Plugin 也先從 JDO 相關的部分開始修改。

在本研究架構設計中 ORM 模組依賴於另一模組 UtbDBService,因為此模組 負責產生符合 Universal Table 資料架構的 SQL 指令及維護此資料綱要的相關資 料表。我們不希望直接在 DataNucleus RDBMS Plugin 中產生符合這些 SQL 指 令,DataNucleus RDBMS Plugin 只需負責執行符合 Universal Table 資料架構的 SQL 指令則可。原因在於 DataNucleus RDBMS Plugin 為開源專案(Open Source Project),會定時的改版升級,如果修改此 Plugin 幅度過大,會增加日後升級到 新版的難度。此外,產生符合 Universal Table 資料架構的 SQL 指令及維護相關 的資料表應由另外的模組負責以達到責任區分的效果,日後中介軟體框架想要增 加支援更多的多租戶 SaaS 資料綱要,只需要另外再新增一模組即可,DataNucleus RDBMS Plugin 也不須大幅的修改。

根據上述的設計決策,修改了九個 DataNucleus RDMBS Plugin 的原始檔案 以及新增一個 Java 檔,修改清單如下:

表 1.1:DataNucleus RDBMS Plugin 修改清單。

新增

1. /org/datanucleus/store/rdbms/art/utb/UTbServiceHelper.java

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

修改

1. /org/datanucleus/store/rdbms/query/JDOQLQuery.java 2. /org/datanucleus/store/rdbms/query/PersistentClassROF.java 3. /org/datanucleus/store/rdbms/request/InsertRequest.java 4. /org/datanucleus/store/rdbms/request/UpdateRequest.java 5. /org/datanucleus/store/rdbms/request/DeleteRequest.java 6. /org/datanucleus/store/rdbms/request/FetechRequest.java

7. /org/datanucleus/store/rdbms/scostore/RDBMSFKListStore.java 8. /org/datanucleus/store/rdbms/sql/SQLStatement.java

9. /org/datanucleus/store/rdbms/sql/SQLText.java

修改 DataNucleus RDBMS Plugin 原始碼的原則為修改幅度越小越好,因此 特別新增了 UTbServiceHelper 這個新的類別,把呼叫 UtbDBService 模組的邏輯 都封裝在此。UTbServiceHelper 類別如下:

圖 3.5:UTbServiceHelper 內部設計。

1. generateUTbSql:呼叫 UtbDBService 模組產生符合 UTB Schema 的 SQL 指令相關的 API,回傳轉換後的 SQL 指令交由 DataNucleus RDBMS Plugin 執行。由於 DataNucleus RDBMS 中 JDOQLQuery 負責執行查詢,

RDBMSFKListStore 與 FetchRequest 則負責執行領域物件中有設定外鍵 關聯的對映查詢,因此修改這兩個類別把原本 DataNucleus 所產生的 SQL

指令,換成由 UTbServiceHelper. generateUTbSql 所產生的 SQL 指令。此 外 UtbDBService 模組需要知道 DataNucleus RDBMS 所產生的 SQL 指令 才能將其轉換成符合 Universal Table 資料架構的 SQL 指令,因此修改原 本 SQLStatement 與 SQLText 類 別 讓 UTbServiceHelper 得 以 取 得 DataNucleus RDBMS 所產生的 SQL 抽象語法樹(Abstract Syntax Tree,

AST),然後在呼叫 UtbDBService 模組前將 DataNucleus RDBMS SQL AST 轉換成 UtbDBService 的 SQL AST,接著再傳遞給 UtbDBService 如此一 來 UtbDBService 才能正常運作。

2. insert、delete、update:呼叫 UtbDBService 模組進行資料的增刪修。

DataNucleus RDBMS 中的 InsertRequest、UpdateRequest、DeleteRequest 分別也是負責處理增刪修的操作,因此修改這三個類別並在增刪修時呼 叫 UTbServiceHelper 的 insert、delete、update 方法。

3. doCustomField、isMTAAnnoated:負責處理租戶修改既有的領域物件欄 位。DataNucleus RDBMS 中與租戶修改既有領域物件相關的類別分別有 PersistentClassROF 、 JDOQLQuery 、 InsertRequest 、 UpdateRequest 、 DeleteRequest 以及 FetchRequest。關於客製 SaaS 既有領域物件將在 3.4.5 中有更加詳細的說明。

藉由修改 DataNucleus RDBMS Plugin,使其與中介軟體框架 UtbDBService 模組合作,中介軟體框架便能實現提供給多租戶 SaaS 開發人員使用 ORM 存取 資料的目標。透過此 ORM 模組多租戶 SaaS 開發人員可使用 JDO 規格對映其領 域物件至 Universal Table 資料架構,並且在查詢資料時可使用 JDO 查詢語法 (JDOQL),不必擔心該如何撰寫出符合 Universal Table 資料架構的 SQL 指令。

3.4.3 UtbDBService

中介軟體框架所使用 Universal Table 資料架構是由 UtbDBService 負責實現,上 一小節的 ORM 模組將依賴於 UtbDBService 模組。如此設計的原因在於不希望

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

實現 Universal Table 資料架構的責任交由 ORM 模組負責,因為中介軟體框架的 ORM 模組是修改 DataNucleus 開源框架,因 DataNucleus 會不斷釋出新版,假如 修改的 ORM 模組當中擔負過多的責任,日後極有可能無法跟上 DataNucleus 新 版的腳步,因此獨立出 UtbDBService 模組來實現 Universal Table 資料架構,ORM 模組只需存取此模組所提供服務即可。根據 3.2 小節框架架構設計,UtbDBService 模組主要任務有三分別為:

1. 產生符合 Universal Table 資料架構 SQL 指令。

2. 當租戶執行新增、修改、刪除資料時維護相關的 Pivot Tables。

3. 當租戶執行新增、修改、刪除領域物件時維護相關的 Metadata Tables。

不過 UtbDBService 模組在實現 Force.com Universal Table 資料架構上並未完 全採用 2.2 小節中所說明的資料表。本研究將先實現 Force.com Universal 資料綱 要的核心,Metadata Tables 實現的為 Objects、Fields 以及 Associations 資料表,

Data Tables 實現的為 Data 資料表,Pivot Tables 實現的為 Indexes、UniqueFields 以及 Relationships 資料表。

圖 3.6:MTA Framework 資料模型。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

Metadata Tables 的 Associations 資料表在 Force.com 的論文中並未提到;按 照其論文中的說明,某 Object 建立與其他 Object 的關聯性後,會在此 Object 的 資料中保存有關聯的 ObjectId 於 Data 資料表的 Value 欄位中,Object 之間的關聯 性 Metadata 並未獨立出來保存。但在實作的過程中發現假設沒有 Associations 這 個資料表來保存 Object 關聯性的 Metadata,會連帶影響無法維護 Pivot Tables 的 Relationships 資料表。

圖 3.7:Associations 資料表。

因為 Relationships 中的 ObjectId 與 TargetObjectId 這兩個欄位的資料無從所 得,必須要有一個資料表來保存 Object 關聯性的 Metadata,Associations 資料表 詳細欄位資訊見上圖。此外,Force.com 的論文中也未提及資料與資料的關聯性 是如何產生的,因此在新增的 Associations 資料表中分別有 FieldId、FieldNum、

TargetFieldId 與 TargetFieldNum 這四個欄位來記錄資料與資料是如何產生關聯 性,就如同在建立一般資料表的外鍵。

假設我們有兩個 Object 分別為 Order 與 Order Lineitem,並為這兩個 Object 建立 Association。從資料模型設計的角度來看,此 Association 的 Source Object 為 Order Lineitem,Target Object 則為 Order,所以此 Association 的 ObjectId 為 Order Lineitem 的 ObjectId,TargetObjectId 為 Order 的 ObjectId。不過 Order Lineitem 中必須有一個 Field 來保存其所對應的 Order 的主鍵值,如同建立外鍵的概念,

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

所以此 Association 的 FieldId 與 FieldNum 為 Order Lineitem 保存 Order 主鍵值的 Field 資訊,TargetFieldId 與 TargetFieldNum 則為 Order 的主鍵 Field 資訊。

新增 Metatdata Tables 的 Associations 資料表後,在實作過程中也發現 Pivot Tables 的 Relationships 資料表有所不足的地方。按照 Force.com 開發白皮書中指 出使用 TenantId、ObjectId、AssociationId、TargetObjectId 複合索引鍵進行查詢,

代表系統已經知道 ObjectId 與 TargetObjectId,系統將使用 Object 的關聯性查出 資料 DataGuid,接著再利用此 Guid 結果再去查詢 Data 資料表,藉此達到 Join 的效果。

但其論文並未說明此 DataGuid 是保存 Object 的 DataGuid 還是 TargetObject 的 DataGuid,而且只保存 Object 的 DataGuid 或 TargetObject 的 DataGuid 是不足 的,因為無法馬上利用 Object 的 DataGuid 或是 TargetObject 的 DataGuid 就可查 出其所關聯的資料之 DataGuid。因此在 Pivot Tables 的 Relationships 資料表中,

新增一欄位為 TargetDataGuid 用以保存 TargetObject 資料的 DataGuid。原本 Relationships 資料表的 DataGuid 欄位則是保存 Object 的 DataGuid,藉由這兩個 欄位將資料關聯性保存起來。

如此一來,假設我們需要知道某筆 Order Lineitem 其所關聯的 Order 資料,

利用該筆的 Order Lineitem 的 DataGuid 至 Relationships 資料表中查詢,馬上便可 知道其對應的 Order 資料的 DataGuid。同樣地,如需知道某筆 Order 所對應的 Order Lineitem 資料,將查詢條件設為 TargetDataGuid 為該筆 Order 的 DataGuid,

便可馬上獲得其所應的 Order Lineitem 的 DataGuid。修改過後的 Relationships 資 料表如下圖所示。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

圖 3.8:Relationships 資料表修改結果。

在實現產生符合 Universal Table 資料架構 SQL 指令的任務中,UtbDBService 模組需要將 ORM 模組傳遞來的 SQL AST 轉換成符合 Universal Table 資料架構 SQL 指令。本研究針對產生 Select、Insert、Delete、Update 的 SQL 指令歸納出 以下規則。

1. Select SQL 指令

由於 Universal Table 資料架構的特性,所有資料都是保存於 Data 資料表,

資料的 Metadata 是保存於 Objects 與 Fields 資料表,因此必須先找出我們查詢的 Object 為何,Object 內擁有其 Fields 的資訊。獲取了 Object 與其 Field 的 Metadata 後,UtbDBService 模組才能產生符合 Data 資料表欄位的資訊與 Where 條件的 SQL 指令。以下為產生 Select 指令規則:

Rule GenerateSelectStatement : Input :

T, the name of object; QL, a list of query fields; WL, a list of where clauses.

Output :

S, the SQL SELECT statement.

Steps :

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

obj = FindObject(T)

S= “SELCT” append GenerateQueryFields(QL, obj) append “FROM Data”

append GenerateWhereClause (WL) return S

function FindObject(T) : Object

return Use T to find Object from Object table

function GenerateQueryFields(QL,obj) : String

return QL map ( x (obj .Fields) => mapping Query Field to Data Table column )

function GenerateWhereClause(WL) :String

return WL map (case IndexField => handle Indexed Field to get DataGuids

case UniqueField => handle UniqueField to get DataGuid case _ => handle Field)

圖 3.9:產生 Select SQL 指令規則。

透過上述的 GenerateSelectStatement 規則可以產生出以下的範例 SQL 查詢指 令。

SELECT Value0 as ProductId,Value2 as UnitPrice,

Value1 as ProductName,Value3 as image1 ,Value4 as image2 , Value5 as note ,Value6 as image3 FROM Data

WHRE ObjectId=3 AND TenantId=1 AND

(DataGuid ='F0AC2C4D-1A1F-4E3C-B4D9-68AEA0EC1CE4' OR Value2>10)

圖 3.10:中介軟體框架產生查詢 SQL 指令。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

2. Insert SQL 指令

產生 Insert SQL 指令的規則主要是將欲新增物件的欄位資訊與欄位資料轉 換成符合 Insert 到 Data 資料的 SQL 指令。

Rule GenerateInsertStatement : Input :

O, an object to be added.

Output :

S, the SQL INSERT statement.

Steps :

Steps :

相關文件