1. 程式人生 > 其它 >ORM查詢語言(OQL)簡介--概念篇

ORM查詢語言(OQL)簡介--概念篇

相關文章內容索引:

ORM查詢語言(OQL)簡介--概念篇

ORM查詢語言(OQL)簡介--例項篇

ORM查詢語言(OQL)簡介--高階篇:脫胎換骨

ORM查詢語言(OQL)簡介--高階篇(續):廬山真貌

一、SQL與ORM

  關係資料庫(RDBMS)的查詢有SQL(Structured Query Language)結構化查詢語言,相比高階程式語言(命令式語言)而言,SQL主要描述想要做什麼,而不是命令式語言的具體如何做,因此,SQL也被稱為第四代語言(4GL),它為現代大多數的關係資料庫系統所支援。SQL的核心是對“關係”的操作,資料庫理論研究證明,SQL是關係上完備的,但是當代大多數高階語言都是面向物件的,高階語言程式要跟關係資料庫進行互動,SQL就成了必須的橋樑,由於SQL基於的“關係”和程式語言的“物件

”是不同的體系,它們之間要完成很好的互動,就得有一個“對映”過程,實現這個過程的程式,就是ORM(Object/Relation Mapping)。

  應用程式呼叫ORM的方法,ORM自動生成相應的SQL語句到資料庫進行查詢,然後ORM將接收到的關係資料對映成實體物件。如果沒有使用ORM,那麼通常應用程式會拆分出一個數據訪問層(DAL)來生成SQL語句並執行相應的查詢。所以,ORM出現後,在一定程度上,它可以取代DAL,這使得你少了一個層的工作量,對於提高工作效率是很重要的。

  下圖是應用程式使用ORM和使用傳統的DAL的一個示意圖。

(圖1:兩種資料訪問架構)

 二、ORM帶來的問題

  使用ORM後,再也不用去寫那些枯燥的DAL程式碼了,不用拼接那些可能存在安全問題或者敲錯欄位名的SQL語句,但是我們發現,僅僅使用ORM它反而喪失了SQL的靈活性,這也是不少人拒絕使用ORM的理由。我們看看很多人的ORM是怎麼定義資料操作介面的,他們常常把這些介面方法由實體類去實現,從而製造一個個充血的實體類:

public interface IEntity<T> where T:class
{
void Add();
void Update();
void Delete();
List<T> GetAll();
T GetOne(int id);
}

使用充血實體類,在使用上還是比較方便的,但是Insert UpdateDelete 都只能操作一條資料,GetAll 方法不僅僅把全部資料拿出來了,而且還可能把不需要的欄位值也拿了出來,那個GetOne方法,也許實際上表的主鍵並不是int 型別的,那麼這些定義就會有問題。。。

  所以,我們見到很多使用了ORM的專案,不管資料是否全部需要,先拿出來再說,不管主鍵是不是int 型別,先定一個方法在那裡,大不了是個空方法,不管當前實體是否需要Delete功能(比如某些系統使用者資料是不能刪除的),都基類給直接實現了。。。。。。

三、ORM查詢語言

 1,分離關注點

  那麼,這些問題ORM能夠解決嗎?ORM本來是完成“物件-關係對映”的,但這裡大多數的ORM都包含了“生成SQL”的功能,而要實現SQL那樣的靈活性,那麼我們必須分離出ORM這個關注點,將“生成SQL”的功能從ORM中抽取出來,這樣我們就能夠有更多的精力致力於發明一個面向物件的,用於ORM查詢的語言,(ORM Query Language) ,這就是OQL

  ORM查詢語言,其實早就有了,從早期的Hibernate的HQL,到MS的Linq(Linq2SQL,EF其實內部都是使用Linq生成的SQL),它們都可以生成複雜的SQL語句,它們都是直接作用於ORM框架的。幾乎在與Linq同一時期,PDF.NET也發明了自己的ORM查詢語言,稱為OQL。下面提到的OQL,都是指的PDF的OQL。

2,PDF.NET的ORM框架

  PDF.NET的ORM框架包括4個部分:

  1. Entity Object :PDF.NET實體類,它繼承於基類 EntityBase,使得每一個實體類都成為一個“資料容器”;
  2. OQL:ORM查詢語言,以實體類物件為操作物件,生成查詢表示式,供實體查詢物件使用。
  3. AdoHelper:資料訪問提供程式抽象類,封裝了對ADO.NET的各種訪問,包括事物操作;框架預設提供了OledbProvider、OdbcProvider、AccessProvider、SqlServerProvider、OracleProvider等,要支援更多的資料庫,只需要繼承AdoHelper即可。
  4. EntityQuery<T> :實體查詢物件,它是一個O/R Mapping物件,它操作涉及的物件型別是一個實體類(型別T);在物件內部,它會把OQL轉換成SQL,然後呼叫AdoHelper完成查詢。

 (圖2:PDF.NET OQL 架構)

  如果僅從查詢呼叫端來觀察,我們發現OQL,跟SQL邏輯上是等價的,一個是“物件化”的查詢,一個是“結構化”的查詢:

物件化查詢:OQL->ORM-> Entity Objects

等於

結構化查詢:SQL ->DB-> DataSet

  如果最終效果Entity Object==DataSet,那麼OQL==SQL

  所以,OQL的設計目標,就是要它生成的SQL語句效果基本達到手寫的SQL語句一樣。由於SQL的具體實現又有很多不同的版本,所以很多時候SqlServer用的SQL語句在Oracle 上不一定能夠使用,只有那些完全標準的SQL語句才是通用的,因此,OQL的設計,也必須是這樣標準的SQL規範,目前,實現的是SQL92標準規範。

3,OQL查詢正規化

  下面是OQL支援的查詢正規化舉例,注意下面的定義裡面使用了“BNF”正規化,為了避免大家誤會,這裡補充下BFN的內容,詳細內容請參考這個連結:http://baike.baidu.com/view/1137652.htm

巴科斯正規化的內容

  在雙引號中的字("word")代表著這些字元本身。而double_quote用來代表雙引號。

  在雙引號外的字(有可能有下劃線)代表著語法部分。

  尖括號( < > )內包含的為必選項。

  方括號( [ ] )內包含的為可選項。

  大括號( { } )內包含的為可重複0至無數次的項。

  豎線( | )表示在其左右兩邊任選一項,相當於"OR"的意思。

  ::= 是“被定義為”的意思。

1,資料查詢:

OQL q=OQL.From(entityObject)
[.[InnerJoin|LeftJoin|RightJoin](entityObject2).On(entityObject.PK,entityObject2.FK)]
[.[InnerJoin|LeftJoin|RightJoin](entityObject3).On(entityObject.PK,entityObject3.FK)]
.Select([entityObjectX.Property1][,entityObjectX.Property2][{,…}])
.Where([<entityObject.Property1>[,entityObject.Property2][,…]]|[OQL2]|[OQLCompare])
.GroupBy(entityObjectX.PropertyN,<"asc">|<"desc">)
.HavingBy(entityObjectX.PropertyM)
.End;

 如果需要分頁,僅需要這樣操作:

q.Limit(分頁大小[,頁碼[,總記錄數]]);

 執行該方法,會生成特定資料庫平臺的分頁SQL語句。

2,資料統計:

OQL q=OQL.From(entityObject)
.Select().Count(entityObject.PropertyX,<””>|<"CountAsName">)
.Where([<entityObject.Property1>[,entityObject.Property2][,…]]|[OQL2]|[OQLCompare])
.End;

3,資料更新:

OQL q=OQL.From(entityObject)
.Update([entityObject.Property1][,entityObject.Property2][{,…}])
.Where([<entityObject.Property1>[,entityObject.Property2][,…]]|[OQL2]|[OQLCompare])
.End;

4,資料刪除:

OQL q=OQL.From(entityObject)
.Delete()
.Where([<entityObject.Property1>[,entityObject.Property2][,…]]|[OQL2]|[OQLCompare])
.End;

下篇我們將使用例項來講解OQL的具體使用,敬請期待。

注:PDF.NET現在已經開源,有關框架的詳細資訊,請看官網介紹:http://www.pwmis.com/sqlmap

 開源資訊介紹:

節前送禮:PDF.NET(PWMIS資料開發框架)V4.5版開源

---------------------分界線-----------------------------------------

文章釋出後,熱心網友 對我提了一些意見,由於不涉及個人隱私,這裡貼上他的原文,如果他看到有異議的話請及時跟我聯絡。在此感謝他提出的下列意見!

另外大家覺得好請點個推薦,反對的話請留個理由,謝謝。

---------------------分界線-----------------------------------------

 shawn(630235793) 1:10:46 大體瀏覽了一下,感覺還不錯

shawn(630235793) 1:14:32 只是博文過於技術細節化而缺少了框架解決的具體問題域、面向的使用者型別,以及整體架構思想與基於關係資料訪問框架的差異性描述,讓讀者一上來很難理解ORM框架的意圖。

回覆:

這些問題的確沒有表述清楚,也是因為我的撰文水平有限,沒有想到這些問題,也不知道該怎樣來表述。

PDF.NET的OQL要解決的主要問題就是讓ORM操作能夠有SQL那樣的靈活性,現有大多數ORM框架都是基於CRUD方法級別的操作,還沒有像SQL那樣具有語言級別的操作,要不然它怎麼會被稱為4GL呢?現在,我覺得LINQ也具有了這樣的能力,而我框架中的OQL,也有這樣的能力,所以我大膽的稱呼它是一個“ORM Query Laguage”,就像SQL是提供給RDBMS的查詢引擎使用一樣,OQL是提供給ORM使用的。

所以,OQL面向的使用者是那些喜歡ORM方式來訪問資料庫,又喜歡SQL的靈活性的技術人員,或者是提供給喜歡其中一種(ORM或者SQL)而不太喜歡另外一種方式的人,讓他們有機會體會到另一種方式的優勢。

整體思想就是,用面向物件的方式來操作資料庫,用OO的方式來寫SQL!

PS:OQL與LINQ相比,它更接近於SQL風格,用慣了SQL的人,第一次接觸LINQ是很不習慣的,至少我是如此。

shawn(630235793) 2012-10-6 1:39:15 資料訪問框架設計的初始設想,首先應該是滿足呼叫層的使用要求,換句話說請求是事務性的,還是非事務性的。如果使用者的請求是事務性的,在訪問層應該提供事務性的處理機制。而不是應用層自己來對是否事務性進行處理。這些應該放在訪問層的對外互動介面處提供給使用者來選擇比較合理。 所以,框架內部的分層,我感覺還應該再多考慮一下比較好。

回覆:

實體層的介面是有的,只是這個圖裡面不好放置而且不是重點,省略了。 是否使用事物,是放在訪問層的對外互動介面處提供給使用者來選擇的。

shawn(630235793) 2012-10-6 1:47:13 畢竟資料訪問框架對於使用者來講就應該遮蔽所有資料庫之間操作的差異性,所有與資料庫相關的一切操作都封裝於內部。對於使用者來講這些都是完全不必去考慮的,只需要提出具體請求是什麼就可以了。對於如何解讀使用者請求、如何根據使用者選擇的具體資料庫,而將請求翻譯成底層資料庫操作指令等等,這些都是訪問層內部機制完成的。

回覆:

正如你所說,框架正是這樣去做的,OQL遮蔽了SQL不同資料庫之間的差異,它會根據具體使用的資料庫,去生成本地化的SQL。

廣州-海華²º¹²<[email protected]>  17:04:10 跟 linq 有什麼相似/區別? 廣州-海華²º¹²<[email protected]>  17:05:45 這篇博文裡主推的理念,讓人想到 linq。 pdf.net 主推的應該是:linq 般好用,但是效能卓越

回覆:

LINQ是.NET獨有的特性,“語言整合查詢”,它是整合在.NET語言中的,這是它的先天優勢。LINQ基於表示式樹,所以它要求必須是.NET平臺而且框架版本要求在.NET3.5及以上。

PDF.NET的OQL跟LINQ一樣都是ORM框架使用的語言,但是OQL語法更接近於SQL,很容易上手,而且,OQL沒有使用.NET的高階特性,這使得它只要是面向物件的語言而且支援泛型即可實現,因此將它移植到C++、Java是完全可能的,而且在.NET平臺上,它也僅需.NET2.0版本的支援。