第三章 可調性軟體框架之設計
3.1 Model
3.1.1 Entity 與實體資料表對映
Controller 及 View 依序進行說明。其中本研究提出之可調性部分可以讓框架應用於不 同的綱要映射技術,此部分建構在框架的Model 部分,不論租戶採用何種綱要映射技 術,都是使用同一個Entity 工廠。因此對於 MTA Application Designer 來說,設計 Application 時不須預測租戶將要使用何種綱要映射技術。也就是說在本研究提出的可 調性多租戶軟體框架下,Application 可應用在不同的綱要映射技術。
3.1 Model
當我們開發多租戶的Application 時候,為了使 Application 所使用的關聯式資料庫具有 支援多租戶的能力,我們需要依照系統及租戶的特性選擇適合的綱要映射技術,但無
論何種選用哪一種映射技術,租戶的邏輯資料表對映到我們選擇的綱要映射技術SQL
Command 都要做些改變,例如 Private Table Layout 需要變更表格或者資料庫名稱,
Universal Table Layout 需要增加 TenantId 與 EntityId 的 Where 條件及各 Value 實體欄位
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
17
與邏輯欄位名稱的對映,Extension Table Layout 則需要 Join table。
在 OOP 中我們通常透過 ORM 技術來操作資料表,因此實務上我們要解決的邏輯 資料表與實體資料表的對映,需要轉換為Entity 與實體資料表的對映問題,而目前許 多ORM 框架的發展日漸完備,透過一些使用上的技巧是可以辦到 Entity 與實體資料表 對映,在.NET 中 LINQ 與 Entity Framework 的搭配就是一個例子,以下將分別探討 Entity 與實體資料表對映在 Universal Table 與 Private Table 如何實做,但暫時不考慮因 為租戶之間的Entity 不同,而需要執行時期動態產生租戶 Entity 的技術,故本小節實 作研究屬於接下來給動態產生Entity 技術的實作藍圖。
3.1.1.1 Entity 對映 Universal Table Layout
我們以一個簡單的例子來說明,假設有一個多租戶的客戶管理系統,系統中有一個 Domain-Entity 叫做 Customer 用來記錄客戶資料,系統原本設計有兩個欄位分別為 Name 與 Phone,而 A 租戶新增了一個 Age 欄位,如此我們使用 Universal Table Layout 會做產生如下的對映。
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
18
圖3.1 Entity 與 Universal Table Layout 對映示意圖
左邊是 Entity,右邊是 Universal Table Layout 實體資料表,也就是 Force.com Universal Table 模型中的 Data 資料表。本研究使用可調性多租戶實體模式,來實做 Entity,每個 Entity 必定有的三個 Property,GUID、TenantId 及 EntityId 由 MtaEntity 提 供。由MTA Application 提供的為 Domain-Entity,它繼承 MtaEntity 並提供 Name 與 Phone 這兩個 Property,。而執行時期,真正提供給租戶的為 Tenant-Entity,他繼承 Domain-Entity,並提供客製化的 Property,例如本例 A 租戶新增的 Age。
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
19
圖3.2 可調性多租戶實體模式
如下圖範例資料,為了易於說明TenantId 與 EntityId 使用 int 而不使用 Guid 型 態,Value0、Value1 及 Value2 則在 TenantId 與 EntityId 的值皆為 1 的資料中分別對映 了Name、Phone 及 Age。
圖3.3 Universal Table Layout Data 資料表,資料範例
如果是非多租戶的Application 中使用 ORM 框架,表示 Entity 可以用相同的名稱 及Property 名稱對映到實體資料表。但若在多租戶 Application 選擇了使用 Universal
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
20
Table Layout,那 Entity 對映資料庫之前就需要將 SQL Command 轉換表格名稱與欄位 名稱,並加上TenantId 與 EntityId 的 Where 條件才能正確取得租戶資料。
要實做這樣的轉換技術,本研究使用Entity Framework 的 Code First 並配合一些技 巧來達成。我們依照可調性多租戶實體模式類別圖使用Entity Framework 來實做 Entity 對映Universal Table Layout,先撰寫 MtaEntity-Class。
程式碼3.1 MtaEntity POCO
MtaEntity 共有 GUID、TenantId 及 EntityId 三個 Property,並且將 GUID Property 設定為Key,MtaEntity 屬於可調性多租戶軟體框架提供的 Class。MTA Application Designer 在開發系統時需撰寫 Domain-Entity 繼承 MtaEntity 並所有的 Property 都須加 上virtual 修飾詞,以提供 Tenant-Entity override。
程式碼3.2 Domain-Entity POCO 範例
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
21
程式碼3.3 Universal Table Tenant-Entity POCO 範例
要取得資料時,可以搭配LINQ 加入 TenantId 與 EntityId 的條件如【程式碼 3.4】
所示,取得租戶編號為1、Entity 編號為 1 且 Phone 為 0900-000-001 的範例程式碼。執 行時使用SQL Server Profiler 觀察,其結果如【圖 3.4】,這段 LINQ 經由 Entity
Framework 對 SQL Server 下達 SQL Command,將條件中的 Phone 轉為 Value1。
程式碼3.4 LINQ 查詢租戶資料
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
22
圖3.4 SQL Server Profiler 觀察查詢資料 SQL Command
圖3.5 SQL Server Profiler 觀察新增資料 SQL Command
但由於 Code First 有兩個問題存在,所以使用單純的 Code First 無法確實適用於多 租戶的Entity 對映到實體資料表,須加上一些技巧。
第一個問題,由於 Code First 的概念是先寫 Entity,執行時再自動建立資料庫與程 式碼。而Entity 變更後再使用 Code First 的 Migration 機制,依照 Entity 來變更資料 表。由於使用Universal Table Layout,Entity 的 Property 一定少於 Data 資料表的 Value 欄位,所以會有許多Value 欄位沒被對映到,因此正規的使用 Code First 無法應付這種 狀況,但Code First 另有一個特性,就是如果 Table 不是經由 Code First 所建立,那 Entity Framework 只會進行對映工作,不會去檢查對映的欄位數量是否一致,因此只要 事先建立好Data 資料表就可以。
‧
3.1.1.2 Entity 對映 Private Table Layout
Private Table Layout 與一般開發 Application 使用的資料表最為接近,要實作 Private Table Layout 在概念上可分為兩種方式。第一種為變更資料表名稱:所有租戶的資料表 都放在同一個資料庫內,但資料表各自獨立,租戶的資料表區隔可在資料表名稱前或 後加上租戶代號,以識別不同租戶擁有的資料表,取用時資料表需要依租戶變更資料 表名稱。第二種為變更連線資料庫:擁有自己的資料庫,因此資料表名稱保留不變,
取用時須變更連線到不同的資料庫。變更資料表名稱的方式在上一小段實作Universal Table Layout 已經使用過,故本小段以變更連線方式為例,依例子可以很容易轉換為變 更資料表名稱的做法。
Entity 對映 Private Table Layout 使用 Code First 在對映上非常容易做到,這在 Code First 第一次建立資料表時是沒問題的。本小段持續使用上一小段提出的可調性多租戶 實體模式,MtaEntity 與 Domain-Entity 都維持不變,僅對執行時期可調性多租戶軟體 框架產生的Tenant-Entity 提出改變,以下列 Tenant-Entity 產生原則提供參考。
1. TenantId 與 EntityId 沒有對映的必要,可宣告為 NotMapped。
2. Domain-Entity 已經宣告的 Property 無須再 override。
3. Domain-Entity 已經宣告的 Property,如果要增加 Attribute 則需宣告。
相較於 Universal Table Layout 的 Tenant-Entity 產生原則,由於 Tenant-Entity 名稱 與Property 名稱不須轉換,Tenant-Entity 的實作上也簡便很多,依原則實做的程式碼如
【程式碼3.5】所示,其中 Name 因為變更為最大長度 50,所以需要提出來做
override,此段程式碼執行後,會自動建立資料庫與 Table,產生資料綱要如【圖 3.6】
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
24
所示。
程式碼3.5 Private Table Tenant-Entity POCO 範例
圖3.6 Code-First 自動產生之資料綱要
但在Code-First 中為了管理 Entity 與資料庫中 Table 的一致性,Entity 變更後都需 要執行Migrations,將 Entity 的變更修改到 Table。Migrations 區分為三種,分別為自動 移轉、手動移轉及程式移轉,預設為自動移轉。自動移轉與手動移轉實務上較常使 用,這兩種移轉方式需要在Visual Studio 中的 Package Manager Console 執行
Migrations 指令。但因為最終我們要產生的 Tenant-Entity 是執行時期動態產生,因此不 適合這兩種移轉方式。所以我們需要使用的是程式移轉,讓Tenant-Entity 變更後可以 直接變更資料表。若採用租戶有獨立資料庫的方式,還要解決如何讓每個租戶可以使 用不同連線,因此本小段目標是實作程式移轉的Entity Framework,並且使其加入可變 動不同連線的機制,以作為本軟體框架執行時產生Model 的設計藍圖。
‧ 國
立 政 治 大 學
‧
N a tio na
l C h engchi U ni ve rs it y
25
因此我們為Entity 所在的 Model 加入程式移轉的設定與 Class,那 Tenant-Entity 變更就不需要在 Package Manager Console 執行 Migrations 指令,而會在應用程式 執行時,由Entity Framework 變更 Table Schema。我們做一個簡單的模擬實驗,租戶在 Customer 新增一個 Address,Tenant-Entity 模擬程式與執行後 Table Schema 如【程式碼 3.6】與【圖 3.7】所示。
程式碼3.6 Private Table Tenant-Entity POCO 範例(修改後)
圖3.7 Code-First 自動修改之資料綱要
由以上的模擬實驗可以確認,這適用在 Private Table Layout 來管理租戶的實體資 料表綱要。若需要變更連線,這部分只要預先設定可用連線在Web.config 的
connectionStrings,並變更 DbContext 建構元的傳入參數就可以達到。
‧
負責提供Entity 於可調式多租戶軟體框架運作時共同必要的 Property。Domain-Entity 繼承MTA-Entity,它是 Development-Time 由 MTA 應用程式開發團隊設計,為應用程 式提供服務必要的Property。而 Tenant-Entity 繼承 Domain-Entity 由可調性多租戶軟體 框架於Run-Time 產生出來,除了依據租戶的客製化資訊提供租戶真正需要 Property 之 外,還依租戶選用的綱要映射技術調整Tenant-Entity 的 Attribute 以提供 EntityFramework 完成對映實體資料表。
由以上實作模擬程式的實驗可知,在可調性多租戶實體模式中,租戶選用不同的 綱要映射技術,只會在執行時期所產生Tenant-Entity 的 Attribute 上有所不同,只要依 照可調性多租戶實體模式實做,就可以讓多租戶軟體框架具有可調性。但解決Entity 與實體資料表對映之後還有其他問題,將在後面的小節一一提出並提出解決方案。