第190期 / August 8, 2013

分享到臉書!分享到維特!分享到噗浪!分享到Google+!分享到微博!轉寄友人友善列印

使用C# Custom Object與Oracle User-Defined Types

作者/洪坤德

[發表日期:2013/8/5]

前言

大部分的應用程式都必須考量與資料庫連結與溝通的部分,儘管跨平台之間的傳輸因軟硬體的進步,其對效能的影響已經越來越小,但若能在程式撰寫上盡量降低跨平台的溝通次數,對於效能的提升才能有比較多的幫助。C#中所使用的Custom Object 以及Oracle的 User-Defined Types(以下簡稱UDTs)即為該語言為了提高效能所定義出來的物件類型,一般在撰寫程式時,不同的methods之間的參數傳遞也會直接使用DTO,除了簡化程式的複雜度,未來程式的擴充也會比較簡單;Oracle亦是PL/SQL中,無論是Function還是Procedure亦可採用UDTs作為其傳遞之參數。這篇文章主要是簡單介紹DTO及UDTs以及如何直接將兩者做對應,降低程式的複雜度及提高效能。

Custom Object

C#常見的Custom Object 為Data Transfer Object (以下簡稱DTO),DTO是屬於一種類別,剛開始建立DTO有幾個目的:

一、跨應用程式的使用費時:

多個應用程式之間,藉由網路的方式將資料進行傳遞、運算或處理,雖然Framework簡化了相當多程序步驟,但資料的序列化以及加密等,都是需要耗費時間的。

二、網路的效能:

網路本身的效能也是需要考量的原因,有時網路架構所產生的Delay遠比傳輸量的影響來的大,也就是說傳遞1000個字跟10個字所花的時間可能差不多,因此在特定的傳輸大小內,次數的影響更勝於一次的傳輸量。

參考MSN上的說明,資料的傳輸過程中若涉及跨平台的傳輸,藉由網路的傳遞必須花費不少時間,同時若有多項資料必須傳遞,對效能的影響相當的大。如下圖所示,為了取得完整的資訊必須耗費四次的傳遞。


《圖一》沒有使用DTO的傳遞
資料來源:MSDN http://msdn.microsoft.com/en-us/library/ff649585.aspx



《圖二》使用DTO的傳遞
資料來源:MSDN http://msdn.microsoft.com/en-us/library/ff649585.aspx


如圖二採用 DTO後,最明顯的優點在於降低跨平台間的傳輸次數,除了提高效能外,傳送的過程中亦可隱藏資料的內容,自訂的DTO也有助於提高程式的可維護性。DTO的撰寫範例如下,於專案中新增一類別(名稱可以自訂),在類別中加入所需要的資料類型及名稱,如下圖。


《圖三》簡易DTO範例


另外Oracle所提供Custom Object的正是UDTs,其撰寫的範例如下圖。


《圖四》Oracle UDTs範例


使用DTO及UDTs的方式相當容易,C#中DTO的命名空間(甚至可以直接拿掉)必須與主程式相同,使用的範例如下。


《圖五》DTO的使用方式


Oracle UDTs的方法亦同,必須注意Schema必須要相同或者是具備使用該UDTs的權限才行。在PL/SQL中的使用範例如下。


《圖六》Oracle UDTs的使用方式


Oracle Store Procedure

大部份資料庫具有其專屬的擴充語言,如PL/SQL、T-SQL,根據Gartner 2012 Worldwide RDBMS Market Share Reports 顯示,Oracle佔全球關聯資料庫軟體市場收入的48.3%,遠遠大於其他四名相近的競爭者,這代表有相當大比例的企業採用Oracle所提供的資料庫產品。作為Oracle專有的SQL擴充語言,PL/SQL(Procedural Language/SQL)其優點如下:

一、與SQL緊密結合:

除了能使用所有SQL的功能外,更可在數字及字串之間隱含轉換,數據不必特別處理;再加上PL/SQL能立即的針對SQL執行結果進行處理,只要例外條件撰寫完全,更可針對不同的SQL例外進行不同的處置。

二、安全性:

PL/SQL Store Procedure將程式碼存放於伺服器端,除了提高隱密性外,使用者只能藉由既定的規則去操作資料庫,無法自行執行SQL語句,確保每位使用者的要求皆可在預期的邏輯之中,提高了資料庫的可維護性及安全性。

三、支援物件導向(Object-oriented programming):

Oracle所提供Object Type支援了物件導向的程式設計,藉此降低成本及開發時間。

四、更好效能:

在沒有採用PL/SQL時,應用程式若需要多次運行SQL,除了容易對網路產生影響外,多次的I/O對於效能也會產生不小的代價;若採用PL/SQL,可將其多次SQL寫在同一個PL/SQL的區塊中,藉此降低網路及I/O;而最好的方式則是搭配PL/SQL中的Store Procedure,由於Store Procedure預存在server端,因此其運行效率相當的高,同一個應用程式的要求,可以執行大量工作內容。

撰寫Store Procedure並不難,其架構大概分為四塊,分別式Header、Declaration Section、Execution Section以及Exception Section,如下圖。


《圖七》Oracle程式架構


一般來說在Header撰寫該Procedure之名稱及參數需求、在Declaration Section中撰寫需要用到的內部參數、程式運作邏輯則寫在Execution Section中,最後Exception Section則是例外控制的部分,最簡易的方式如下圖,未包含Declaration及Exception。


《圖八》Oracle Store Procedure


C# & Oracle Store Procedure

在應用程式中呼叫Oracle Store Procedure並不難,只需要指定Command Type為Store Procedure並且把對應的參數傳送過去即可。範例如下:


《圖九》C#主程式



《圖十》Oracle Store Procedure


上圖九為C#的主程式內容,而需要傳入的參數則依據圖11 Store Procedure的定義即可,不過這樣的寫法在面對到大量的資料時,就會出現困擾。一般來說,應用程式本身會根據不同的需求實作DTO、Array等以簡化程式的複雜度,每個物件裡所包含的資料可能會高達幾十種,此時若依舊使用上述的方式,不只程式冗長且維護也不便,在Oracle端也會產生相同的困擾。

C# DTO & Oracle UDTs

DTO與UDTs兩者的概念相似,藉著將兩者對應降低程式的複雜度、提高可維護性以及程式撰寫的品質,範例主程式如下,該程式的目的在於將玩家的資料以DTO的型態傳進Oracle中,在Store Procedure中更改其年齡後傳出,其中所用到的DTO名稱為:PlayerDto、Store Procedure名稱為:AlterPlayerAge、Oracle UDTs為:PLAYER。


《圖十一》使用DTO主程式範例



《圖十二》Store Procedure 範例



《圖十三》Oracle UDTs 範例


為了將C#裡的DTO直接傳入Store Procedure與其UDTs對應,必須要在原本的DTO做些加工,大致如下:

一、參考Oracle.DataAccess.Client及Oracle.DataAccess.Types:

前者是為了與Oracle連線,必須使用到OracleConnection Object;後者則是為了DTO與UDTs的對應Type需不同的Attribute做對應。

二、增加Oracle Object Mapping Attribute:

在每個Property上增加Oracle 所對應的Attribute名稱,例如在string Name{get;set;}上加入[OracleObjectMappingAttribute("NAME")]其中括號中的名稱一定要全部大寫。

三、實作FromCustomObject及ToCustomObject methods:

應用程式本身可能會將DTO傳入或從Oracle讀出,再加上DTO需繼承IOracleCustomType,因此必須實作FromCustomObject及ToCustomObject。

四、撰寫Inner Class 並實作CreatObject methods:

主要的Type對應則寫在Inner Class,該Class必須繼承IOracleCustomTypeFactory並且實作CreatObject,其中對應到的Oracle Type名稱也必須要是大寫。


《圖十四》C#端DTO範例



《圖十五》執行結果


C# ARRAY & Oracle UDTs VARRAY

Array等Collection亦是應用程式常見的型態,將Collection傳進Oracle中也必須要有對應的UDTs Varray才可以。範例主程式如下,該程式的目的在於將隊伍成員的資料以Array的型態傳進Oracle中,在Store Procedure中更改其成員姓名後傳出,其中所用到的Array名稱為:TeamMerber、Store Procedure名稱為:AlterTeamMember、Oracle UDTs為:TEAMMEMBER。


《圖十六》使用Array主程式範例



《圖十七》Store Procedure 範例



《圖十八》Oracle UDTs 範例


為了將C#裡的Array直接傳入Store Procedure與其UDTs對應,必須要在原本的Array做些加工,大致如下:

一、參考Oracle.DataAccess.Client及Oracle.DataAccess.Types。

二、實作FromCustomObject及ToCustomObject method:因該包含Array之DTO需繼承IOracleCustomType,因此必須實作FromCustomObject及ToCustomObject。

三、實作CreatObject 、CreateArray以及CreateStatusArray methods:Inner Class必須繼承IOracleCustomTypeFactory以及IOracleArrayTypeFactory並且實作CreatObject、CreateArray以及CreateStatusArray,其中對應到的Oracle Type名稱必須要是大寫。


《圖十九》C#端Array範例



《圖二十》執行結果


C# DTO ARRAY & Oracle UDTs TABLE

進一步的應用則是以存放DTO的Collection作為參數傳入Oracle中,其對應的UTDs即為Table,範例主程式如下,該程式目的在於將包含隊伍成員資料的DTO以Array的型態傳進Oracle中,在Store Procedure中更改其成員姓名後傳出,其中所用到的DTO ARRAY名稱為:TeamWithPlayer、Store Procedure名稱為:AlterTeamWithPlayer、Oracle UDTs為:TEAMWITHPLAYER。其中TeamWithPlayer使用了第一個範例中的DTO class,因此其對應方式如C# DTO & Oracle UDTs說明。


《圖二十一》使用Array主程式範例



《圖二十二》Store Procedure 範例



《圖二十三》Oracle UDTs 範例


為了將C#裡的Dto Array直接傳入Store Procedure與其UDTs對應,必須要在原本的Dto Array做些加工,大致如下:

一、參考Oracle.DataAccess.Client及Oracle.DataAccess.Types。

二、實作FromCustomObject及ToCustomObject method:因該包含Array之DTO需繼承IOracleCustomType,因此必須實作FromCustomObject及ToCustomObject。

三、實作CreatObject 、CreateArray以及CreateStatusArray methods:Inner Class必須繼承IOracleCustomTypeFactory以及IOracleArrayTypeFactory並且實作CreatObject、CreateArray以及CreateStatusArray,其中對應到的Oracle Type名稱必須要是大寫。


《圖二十四》C#端Array範例



《圖二十五》執行結果


總結

Oracle的UDTs只分為Object 及Collection,因此C# Custom Types對應時只需考量要對應的UDTs類型,對Object而言,在C# Custom Types必須要實作IOracleCustomType以及IOracleCustomTypeFactory中的method;而對Collection而言,除了實作上述兩個介面外,還需要額外實作IOracleArrayTypeFactory。剩下的,只需要將對應的Mapping Attributes指定上去即可,Oracle官方文件有提供所有UDTs與C# Custom Type對應的表格,如下表。


《表一》UDTs與C# Custom Type對應


將C#的Custom Object 與 Oracle UDTs對應後,程式撰寫也會方便許多,兩種不同的平台之間的溝通也能最簡易,對於程式的品質一定也會有很大的幫助。

參考資料

Oracle User-Defined Types (UDTs) and .NET Custom Types。
Interaction between C# Application and Oracle through Custom Object。
Data Transfer Object。
Gartner 2012 Worldwide RDBMS Market Share Reports。