(廣州大學 計算機科學與網(wǎng)絡(luò)工程學院, 廣東 廣州 510006)
數(shù)據(jù)庫應(yīng)用廣泛,每天有無數(shù)的開發(fā)人員在書寫與數(shù)據(jù)庫交互的代碼,這些交互代碼可以由程序員純手動編寫,也可以使用現(xiàn)有的專業(yè)ORM框架工具生成.目前,可用的專業(yè)ORM框架工具很多,如Hibernate[1]、ADO.NET Entity Framework[2]等.Hibernate是一個開放源代碼、全自動的ORM框架,可以自動生成SQL語句、自動執(zhí)行,使得Java程序員可以使用對象編程思維來操縱數(shù)據(jù)庫.ADO.NET Entity Framework是微軟以 ADO.NET為基礎(chǔ)所發(fā)展出來的ORM解決方案[3].Entity Framework 利用了抽象化數(shù)據(jù)結(jié)構(gòu)的方式,將每個數(shù)據(jù)庫對象都轉(zhuǎn)換成應(yīng)用程序?qū)ο?,讓?shù)據(jù)庫的E-R模型完全轉(zhuǎn)成對象模型.此外,還有其他的一些專業(yè)的ORM框架,如Mybatis[4]、NHibernate[5]、Speed[6]、SqlBuilder.NET[7]等,文獻[8]提出了云計算環(huán)境下的一種基于Hbase的ORM設(shè)計方案.這些專業(yè)的ORM框架工具生成的代碼的優(yōu)點是功能豐富,使用比較方便、靈活,但也存在一些問題:
(1)有些框架代碼的執(zhí)行需要動態(tài)生成SQL,并通過相應(yīng)的配置信息完成對象與關(guān)系之間的映射,因此,執(zhí)行效率不高[9];
(2)當ORM框架的版本更新時,程序員使用ORM框架的代碼也需要更新,因此,代碼隨ORM框架版本的改變而改變;
(3)ORM框架只支持部分關(guān)系數(shù)據(jù)庫或部分程序設(shè)計語言;
(4)ORM框架比較復(fù)雜,程序員需要進行培訓(xùn)學習才能熟練掌握ORM框架的使用.
基于以上原因,很多對執(zhí)行效率有要求的項目以及不提供ORM框架的關(guān)系數(shù)據(jù)庫,都必須采用純手工編寫數(shù)據(jù)庫訪問層的源代碼,但是,純手工編寫數(shù)據(jù)庫訪問層代碼容易出錯,而且需要耗費大量時間.為了減輕開發(fā)人員的工作量,本文提出一種數(shù)據(jù)庫訪問代碼自動生成方法,利用該方法,可以生成“純手工編寫”的源代碼,把開發(fā)人員從枯燥、重復(fù)的數(shù)據(jù)庫訪問代碼編寫工作中解放出來,提高工作效率.
當前,大多數(shù)手工編寫的代碼使用數(shù)據(jù)庫開發(fā)商提供的接口(如JDBC[10]、ADO.net)訪問數(shù)據(jù)庫,使用這些接口訪問數(shù)據(jù)庫需要經(jīng)過“與數(shù)據(jù)庫建立連接、發(fā)送SQL語句并處理結(jié)果”的步驟,這些步驟的源代碼自動生成需要解決三個關(guān)鍵問題:①數(shù)據(jù)庫的數(shù)據(jù)類型與程序設(shè)計語言中的數(shù)據(jù)類型及獲取方法之間的映射關(guān)系;②從數(shù)據(jù)庫的數(shù)據(jù)字典中獲取數(shù)據(jù)庫的元數(shù)據(jù);③自動生成代碼的算法設(shè)計.接下來,本文以C#語言訪問SQL Server數(shù)據(jù)庫的代碼為例,描述訪問代碼自動生成的過程.
(1)SQL Server數(shù)據(jù)類型與c#數(shù)據(jù)類型及獲取方法之間的映射關(guān)系.
SQL Server 和 .NET Framework 基于不同的類型系統(tǒng).針對不同的SQL Server數(shù)據(jù)庫引擎類型,類型SqlDataReader公開了用于返回 .NET Framework 類型的訪問器方法.本文在表1中列出了部分SQL Server數(shù)據(jù)類型與c#數(shù)據(jù)類型及獲取方法之間的映射關(guān)系,詳細的映射關(guān)系參見MSDN文檔[11].
表1 SQL Server數(shù)據(jù)類型映射
(2)從數(shù)據(jù)庫的數(shù)據(jù)字典中獲取數(shù)據(jù)庫的元數(shù)據(jù).
當使用SQL命令在數(shù)據(jù)庫中創(chuàng)建表、視圖、存儲過程時,數(shù)據(jù)庫將表、視圖、存儲過程的元數(shù)據(jù)存儲到系統(tǒng)表中,通過查詢數(shù)據(jù)庫系統(tǒng)表,可以獲取到創(chuàng)建表、視圖、存儲過程的所有元數(shù)據(jù),例如,可以使用以下SQL語句在SQL SERVER中獲取STUDENT表的字段元數(shù)據(jù).
select col.name columnName, tp.name dataType,col.max_length dataLength,col.precision dataPrecision,col.scale dataScale, case col.is_nullable when 1 then 'Y' when 0 then 'N' end isNullable, case col.is_identity when 1 then 'Y' when 0 then 'N' end isIdentity, case col.is_computed when 1 then 'Y' when 0 then 'N' end isComputed,sc.text defaultValue from sys.objects obj inner join sys.COLUMNS col on obj.object_id= col.object_id inner join sys.types tp on col.user_type_id=tp.user_type_id left join syscomments sc on col.default_object_id=sc.id where obj.type in ('U','V') and obj.name ='STUDENT'
每個表或視圖需要獲取的相關(guān)的元數(shù)據(jù)信息包括列名、列數(shù)據(jù)類型、數(shù)據(jù)長度、可否空、是否自增字段、是否自動計算字段、默認值等,如果是數(shù)字,還必須考慮數(shù)字的有效位數(shù)和小數(shù)位數(shù).如果是表,還必須考慮表的約束元數(shù)據(jù),以確定主碼包括哪些字段、外碼包括哪些字段.
對于存儲過程,需要通過系統(tǒng)表獲取存儲過程的名稱、參數(shù)類型、參數(shù)個數(shù)和順序等元數(shù)據(jù),以生成調(diào)用存儲過程的源代碼.
(3)自動生成代碼的算法設(shè)計.
本文設(shè)計了兩種代碼生成算法即常規(guī)代碼生成算法和按SQL生成代碼.常規(guī)代碼生成算法的過程(本文以表為例):①與數(shù)據(jù)庫進行連接,獲取表的元數(shù)據(jù)信息;②根據(jù)獲取的元數(shù)據(jù)信息和表1中的類型映射信息,生成實體類.如圖1所示,表名稱映射為類名稱,表的每個字段映射為類的屬性成員.③根據(jù)獲取的元數(shù)據(jù)信息和生成實體類,生成select、insert、update、delete等SQL語句對應(yīng)的靜態(tài)成員函數(shù).
create table student(sno varchar(10) primary key,sname varchar(20) not null,sage int);public partial class student{public String Sno{get;set;}public String Sname{get;set;}public Nullable
圖1 Student表與實體類student
Fig.1 Student table and student entity class
作為示例,以下生成的代碼是根據(jù)學生的學號獲取對應(yīng)的學生信息,其中,類SqlHelper封裝了訪問數(shù)據(jù)庫的靜態(tài)方法.
public static Student GetObjectByPK(String SNO)
{
Student tmp=null;
string sql="SELECT SNO,SNAME,SAGE FROM STUDENT WHERE SNO=@SNO ";
SqlParameter[] para=new SqlParameter[]{new SqlParameter("@SNO",SqlDbType.VarChar,10)};
para[0].Value=SNO;
using(SqlDataReader sdr=SqlHelper.ExecuteReader(SqlHelper.strCon, CommandType.Text, sql, para))
{
if (sdr.Read())
{
tmp=new Student();
tmp.Sno=sdr.GetSqlString(0).Value;
tmp.Sname=sdr.GetSqlString(1).Value;
if (!sdr.IsDBNull(2))
tmp.Sage=sdr.GetSqlInt32(2).Value;
}
}
return tmp;
}
按SQL生成代碼的方法首先對SQL語句分析,解析出SQL語句中包含的表以及字段信息,然后按照“常規(guī)代碼生成算法”的過程,生成對應(yīng)的靜態(tài)操作方法;對于多表查詢的SQL語句,可以在數(shù)據(jù)庫中創(chuàng)建為視圖,然后按照“常規(guī)代碼生成算法”的過程,生成對應(yīng)的靜態(tài)操作方法.
本文提出一種自動生成“純手工編寫”的源代碼的方法,生成的代碼規(guī)范、易于維護,減輕了程序員的編碼工作,提高了開發(fā)效率.