Grove——.NET中的ORM實現
作者:林學鵬
ORM的全稱是Object Relational Mapping,即對象關係映射。它的實質就是將關係數據(庫)中的業務數據用對象的形式表示出來,並通過面向對象(Object-Oriented)的方式將這些對象組織起來,實現系統業務邏輯的過程。在ORM過程中最重要的概念是映射(Mapping),通過這種映射可以使業務對象與數據庫分離。從面向對象來說,數據庫不應該和業務邏輯綁定到一起,ORM則起到這樣的分離作用,使數據庫層透明,開發人員真正的面向對象。圖 1簡單說明了ORM在多層系統架構中的這個作用。
圖1:ORM在多層系統架構中的作用
目前大多數項目或產品都使用關係型數據庫實現業務數據的存儲,這樣在開發過程中,常常有一些業務邏輯需要直接用寫SQL語句實現,但這樣開發的結果是:遍地佈滿SQL語句。這些高藕合的SQL語句給系統的改造和升級帶來很多無法預計的障礙。爲了提高項目的靈活性,特別是快速開發,ORM是一個不錯的選擇。舉個簡單的例子:在使用ORM的系統中,當數據庫模型改變時,不再需要理會邏輯代碼和SQL語句中涉及到該模型的所有改動,只需要將該模型映射的對象稍作改動,甚至不做改動就可以滿足要求。
本頁內容
一、ORM的工具實現:Grove | |
二、Grove在開發中的實際應用 | |
三、總結 |
一、ORM的工具實現:Grove
優秀的ORM工具不僅可以幫助我們很好的理解對象及對象的關係,而且工具本身會幫助我們維護這些關係。基於這個理念,我設計了基於.NET的ORM工具——Grove ORM Development Toolkit。
Grove ORM Development Toolkit包含Grove和Toolkit兩部分內容。Grove爲ORM提供對象持久、關係對象查詢、簡單事務處理、簡單異常管理等功能。數據持久包括一些對象的Insert、Delete、Update、Retrieve等功能,關係對象查詢則提供一些基於對象的複雜關係查詢,包括對應到數據庫功能的子查詢、關聯查詢(JOIN)、函數支持(count、avg、max、min)、聚合等。Toolkit是基於VS.NET 2002/2003的VSIP開發的外接程序,職責是幫助開發人員快速映射關係數據庫中的業務模型到符合Grove要求的映射實體類,以及映射數據庫中複雜關係查詢到Grove要求的關係映射實體,暫時只提供C#支持。圖 2是Grove內部類實現關係圖。
圖 2: Grove內部類實現關係圖
在ORM實現的前期工作中,爲了實現屏蔽各種數據庫之間的操作差異,我們需要定義數據操作公有接口,封裝基本的數據庫Insert,Update,Delete,Query等操作。
public interface IDbOperator { int ExecNonQuery(string cmdText); int ExecDataSet(string cmdText,DataSet entity); object ExecScalar(string cmdText); … }
再定義一個數據庫操作工廠類,實現各種不同類型數據的適配。
public abstract class DbOperatorFactory:IDbOperator
然後實現各種數據庫的操作類,以SQLServer爲例。
internal class SqlDbOperator:DbOperatorFactory
完成後,就是ORM主角——實體(Entity)的實現。ORM中實體的定義可以通過實體類自身包含數據模型元數據的方式實現,也可以通過定義XML的元描述實現。下面講述了通過實體類自身映射的實現。
實體(Entity)是實際業務數據的載體,包含業務數據模型的元描述,可以直接由數據庫中的某張表或視圖生成,也可以根據需要手工創建。.NET中提供了System.Attribute,該類包含訪問和測試自定義屬性的簡便方法。.NET Framework預定義了一些屬性類型並使用它們控制運行時行爲。我們可以通過繼承System.Attribute基類自定義用於描述實體對象映射時所需要的數據模型元數據,包括表名,字段名,字段長度,字段類型等一些常用的數據。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class DataTableAttribute : Attribute
AttributeUsage用來表示該自定義屬性可以被綁定在什麼樣的對象上,這裏表示應用在Class或者Struct之上。
抽象一些具有相同特徵的屬性,使之成爲自定義屬性的基類。
[AttributeUsage(AttributeTargets.Property)] public class BaseFieldAttribute:Attribute
定義一般字段所需要的自定義屬性類。
[AttributeUsage(AttributeTargets.Property)] public class DataFieldAttribute : BaseFieldAttribute
定義關鍵字字段所需的自定義屬性類。
[AttributeUsage(AttributeTargets.Property)] public class KeyFieldAttribute : BaseFieldAttribute
定義外鍵字段所需要的自定義屬性類。
[AttributeUsage(AttributeTargets.Property)] public class ForeignKeyFieldAttribute : BaseFieldAttribute
在以上自定義屬性類完成後,我們需要一個用於訪問實體在運行期綁定的自定義屬性及屬性數據的一個Help類。
internal class TypeHelper
實體定義完成後,我們需要根據實體類中綁定的自定義屬性構造出運行期需要的SQL語句,爲了收集實體類定義中的數據結構描述,我們需要定義一個類來說明實體在運行期所引用到的所有關於數據持久的信息,包括關鍵字字段,外鍵字段,一般字段等。
internal class TypeInfo
同時需要一個字段元數據描述類,描述字段在數據庫中的名稱,大小,是否可爲空,列類型等信息。
internal class ColumnInfo
以上條件具備後,我們需要定義一個解析類,負責轉換數據的程序類型到數據庫字段類型,並且構造出Insert,Update,Delete,Query等操作所需要的SQL語句。
internal class SqlEntityParser
將上面的操作組合起來就是實體類對象操作員。
public class ObjectOperator
實現新增一個記錄到數據庫中,就是創建了一個新的實體對象,並交由對象操作員進行持久化。
public void Insert(object o) { TypeInfo info1=new TypeInfo(o.GetType());//根據實例或者實體描述信息 SQLCommand sc=info1.BuildInsertCommand(o);//構造SQL命令對象 DbOperator.Parameters=sc.Parameters;//賦值SQL命令所需的參數 DbOperator.ExecNonQuery(sc.CommandText);//執行SQL命令 }
這裏的SQLCommand對象封裝了SQL命令處理時所需要的一些值,包含SQL語句,命令參數(Parameter)等。
二、Grove在開發中的實際應用
安裝Grove Kit要求Visual Studio 2003 及.NET Framework 1.1支持。從Grove網站下載安裝包之後,解壓縮GroveKit.zip,執行安裝。
在GroveKit安裝結束後,打開VS.NET,在VS.NET的啓動畫面上,您會看到Grove Develop Kit的標誌,表示GroveKit已被正確安裝。
2.1生成映射實體類
本文將以C# 項目爲例解釋Grove在開發中的具體應用。項目名WebApp1,操作系統 Windows 2000,數據庫SQL Server 2000,數據庫實例名:WebApp1,表結構定義如下:
表名 | 字段 |
Customers |
CustomerID int(4) PK CustomerName varchar(50) CustomerDesc varchar(200) Status tinyint |
Addresses |
AddressID int(4) PK CustomerID int(4) FK Address varchar(200) |
1. |
在VS.NET中,打開“文件->新建->項目”,在Visual C#項目選擇ASP.NET WEB應用程序,確定後生成WebApp1項目,在項目中添加對Grove.dll的引用,Grove.dll位於GroveKit的安裝路徑下,您也可以通過.NET Configuration將Grove添加到程序集緩存中。 |
2. |
在VS.NET中,打開“工具->Grove Tool Kit”,在GroveToolKit中設置數據庫連接屬性,並保存。 圖3 設置數據庫連接串 |
3. |
配置當前Web項目的web.config(在</configuration>之前加入以下配置) <appSettings> <add key="DBConnString" value="Server=localhost;Uid=sa;Pwd=sa;Database=WebApp1" /> </appSettings> |
4. |
4)在VS.NET解決方案資源管理器中選中Entities,並在GroveToolKit中選擇表名,點擊GroveToolKit的toolbar中的Preview Entity Class按鈕,出現該表的實體映射類預覽窗口。 圖4 預覽實體映射類 |
5. |
檢查當前預覽的實體類,點擊生成文件按鈕,該實體類將被生成到解決方案資源管理器當前選中的路徑下。 |
6. |
重複4,5步驟就可以生成其他表的映射實體類。 Customer.cs using System; using Grove.ORM; [DataTable("Customers")] public class Customer { int _CustomerID; string _CustomerName; string _CustomerDesc; int _Status; [KeyField("CustomerID")] public int CustomerID { get{return this._CustomerID;} set{this._CustomerID=value;} } [DataField("CustomerName")] public string CustomerName { get{return this._CustomerName;} set{this._CustomerName=value;} } [DataField("CustomerDesc")] public string CustomerDesc { get{return this._CustomerDesc;} set{this._CustomerDesc=value;} } [DataField("Status")] public int Status { get{return this._ Status;} set{this._ Status=value;} } } Address.cs using System; using Grove.ORM; [DataTable("Addresses")] public class Address { int _AddressID; int _CustomerID; string _Address; [KeyField("AddressID")] public int AddressID { get{return this._AddressID;} set{this._AddressID=value;} } [ForeignKeyField("CustomerID")] public int CustomerID { get{return this._CustomerID;} set{this._CustomerID=value;} } [DataField("Address")] public string CustomerAddress { get{return this._Address;} set{this._Address=value;} } } 代碼1.實體映射類 |
2.2對象持久化
Grove提供ObjectOperator實現對映射實體對象的數據庫持久工作,並通過IObjectQuery接口實現對複雜數據庫關係映射實體的查詢,主要接口如下:
方法 | 說明 |
Insert |
新增一個對象 |
Update |
根據條件更新一個對象 |
Remove |
根據條件刪除一個對象 |
RemoveChilds |
刪除所有關係對象 |
Retrieve |
返回一個對象 |
RetrieveChilds |
返回所有關係對象 |
GetDataReader |
返回IDataReader |
GetObjectSet |
返回對象集合 |
GetObjectSource |
根據對象定義返回DataSet |
GetCount |
從數據源返回記錄條數 |
BeginTranscation |
在數據庫支持事務的基礎上,開始事務處理 |
Commit |
完成當前事務 |
Rollback |
回退當前事務 |
2.3數據查詢
如一般的關係型數據庫所具有的查詢功能一樣,Grove也有着非常豐富的查詢功能,如對象查詢、函數查詢、子查詢、排序查詢等。這裏對對象查詢做簡單介紹,其它查詢讀者可以自行參考Grove的開發文檔。Grove提供ObjectQuery 幫助ObjectOperator從數據源查詢數據, ObjectOperator 需要通過ObjectQuery解析實體對象中的屬性(System.Arrtibute)定義,並構造查詢語句。ObjectQuery在運行時往往需要定義篩選語句(請參考篩選語句的語法定義)。例如,檢索Customer對象,當State 屬性等於WA的情況:
ObjectQuery query=new ObjectQuery(typeof(Customer),"this.State='WA'");
當檢索需要返回所有對象時,則不需要定義篩選語句
ObjectQuery query=new ObjectQuery(typeof(Customer),"");
2.4篩選語句的語法定義
在ObjectQuery中使用的篩選允許你在定義的時候,根據使用面向對象語法規則進行定義篩選語句。
操作 | 描述 |
!, not |
用於比較布爾型,例如: !Order.CustomerID.Contains(Customer.CustomerID) |
<, >, <= , >= |
用於值比較,例如: Order.Quantity >= 12 |
=, !=, <>, = = |
用於值判斷,例如: Customer.Country = 'USA' and Customer.Region != 'WA' |
and, && |
用於邏輯判斷,例如: Customer.Country = 'USA' and Customer.Region = 'WA' |
or, || |
用於邏輯判斷,例如: Customer.LastName = 'Smith' or Customer.LastName = 'Jones' |
三、總結
以上就是ORM的簡單實現,複雜的關係對象映射及關係映射實體的查詢也是ORM中尤爲重要的一塊處理,爲了屏蔽各數據庫之間的SQL差異,很多好的ORM框架都提供一種符合面嚮對象語言本身語法規則的Query Language支持,例如實現對數據庫函數的支持時,會通過定義一些公開的,與編程語言接近的語言來實現,比如說定義Object.Size(),Object.Sum()等類方法式操作語法,在邏輯判斷的時候提供一些語言本身的邏輯運算符支持,比如c#中的&&表示and,||表示or等等這些一系列的面向對象編程風格的支持,都很好地爲基於關係型數據庫支持的系統開發向“面向對象”提供了有力的支持。Grove目前對關係對象查詢有很好的支持,感興趣可以到Grove的網站了解詳細信息。
注:關於Grove的詳細信息和安裝包,支持站點已經提供了一些相關幫助和下載。http://grove.91link.com