




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、將對(duì)象映射到關(guān)系數(shù)據(jù)庫:對(duì)象/ 關(guān)系映射(O/R Mapping)詳解大多數(shù)現(xiàn)代商業(yè)應(yīng)用開發(fā)項(xiàng)目使用面向?qū)ο蠹夹g(shù),比如采用Java或者C#來創(chuàng)建應(yīng)用軟件,同時(shí)使用關(guān)系型數(shù)據(jù)庫來存儲(chǔ)數(shù)據(jù)。但這并不是要說你沒有其它選擇, 也有許多應(yīng)用程序是使用面向過程的語言開發(fā),比如COBOL,而且也有許多系統(tǒng) 使用對(duì)象型數(shù)據(jù)庫或者XML數(shù)據(jù)庫來存儲(chǔ)數(shù)據(jù)。然而,因?yàn)槊嫦驅(qū)ο蠛完P(guān)系數(shù)據(jù) 庫技術(shù)到目前為止已經(jīng)成為一種事實(shí)上的標(biāo)準(zhǔn),在本章節(jié)中我假設(shè)你正在使用這 些技術(shù)。如果你采用其它的存儲(chǔ)技術(shù),本文里的許多概念仍然適用,只需要做一點(diǎn)點(diǎn)修改(不必?fù)?dān)心,Realistic XML總括了對(duì)象與XML映射的相關(guān)問題)。在項(xiàng)目組
2、通常用來創(chuàng)建以軟件為基礎(chǔ)的系統(tǒng)時(shí),那些技術(shù)中,存在著面向?qū)ο蠹?術(shù)和關(guān)系型技術(shù)之間的阻抗失配。不過這種阻抗失配很容易被克服,秘訣在于兩 點(diǎn):你需要理解把對(duì)象映射到關(guān)系型數(shù)據(jù)庫的過程,以及如何去實(shí)現(xiàn)這些映射。 在本章節(jié)里,“映射”一詞是用來表示如何把對(duì)象和對(duì)象之間的關(guān)系對(duì)應(yīng)到數(shù)據(jù) 庫表以及表之間的關(guān)系。你將很快發(fā)現(xiàn)這并不像聽起來的那樣簡(jiǎn)單易懂,盡管它 實(shí)際上也不是那么的槽糕。目錄敏捷DBA的角色基本概念oShadow信息o映射元數(shù)據(jù)o如何使映射適合全過程繼承結(jié)構(gòu)的映射o整個(gè)層次結(jié)構(gòu)映射到一張表o每個(gè)具體類映射到單獨(dú)的一張表o每個(gè)類單獨(dú)映射到一張表o將類映射為一個(gè)通用的表結(jié)構(gòu)o多重繼承映射 o映射
3、策略之間的比較映射對(duì)象關(guān)系o關(guān)系的類型o如何實(shí)現(xiàn)對(duì)象關(guān)系o如何實(shí)現(xiàn)關(guān)系數(shù)據(jù)庫中的關(guān)系o關(guān)系映射一對(duì)一映射一對(duì)多映射多對(duì)多映射o映射有序集合o映射遞歸關(guān)系映射類作用域(Class-Scope )屬性性能調(diào)優(yōu)o優(yōu)化你的映射o延遲讀取為什么數(shù)據(jù)Schema不應(yīng)該主導(dǎo)對(duì)象Schema實(shí)現(xiàn)方式對(duì)對(duì)象的影響模型驅(qū)動(dòng)體系結(jié)構(gòu)(MDA: Model Driven Architecture)的含義映射技術(shù)模式化參考文獻(xiàn)和閱讀推薦1. 敏捷 DBA 的角色圖 1 顯示了一個(gè)敏捷 DBA 在映射對(duì)象到關(guān)系數(shù)據(jù)庫的過程中所扮演的角色。其中我們關(guān)心 三個(gè)主要的活動(dòng)。1.映射?;镜哪繕?biāo)是決定一個(gè)有效的策略來持久化對(duì)象數(shù)
4、據(jù)。這包括保存單個(gè)對(duì)象 的屬性以及對(duì)象之間的關(guān)聯(lián),同時(shí)也包括那些類之間的繼承結(jié)構(gòu)。2.實(shí)現(xiàn)映射3.性能調(diào)優(yōu)在圖 1 中我們注意到有一個(gè)有趣的事情,敏捷的 DBA 和應(yīng)用程序開發(fā)人員在在這 三個(gè)主要活動(dòng)中都在一起工作。雖然敏捷的 DBA 應(yīng)該確保映射的有效性,但他們 實(shí)際上并不是獨(dú)自對(duì)其負(fù)責(zé)的。與他人協(xié)同工作而不單打獨(dú)斗正是敏捷軟件開發(fā) 成功的關(guān)鍵所在。圖 1. 映射時(shí)敏捷 DBA 的角色。2. 基本概念在學(xué)習(xí)如何把對(duì)象映射到關(guān)系型數(shù)據(jù)庫的過程中,通常是從映射一個(gè)類的數(shù)據(jù)屬 性開始的。一個(gè)屬性可以映射到關(guān)系型數(shù)據(jù)庫里 0 個(gè)或者多個(gè)字段。請(qǐng)記住,不 是所有的屬性都是持久性的,其中的一些只是用做臨
5、時(shí)計(jì)算的。例如,在你的應(yīng) 用程序中一個(gè) Student 對(duì)象可能需要有一個(gè)平均分(averageMark)屬性,但并 不需要存儲(chǔ)到數(shù)據(jù)庫里,因?yàn)樗怯蓱?yīng)用程序計(jì)算得到。一個(gè)對(duì)象的某些屬性可 能本身也是對(duì)象,比方說一個(gè) Customer 對(duì)象擁有一個(gè) Address 對(duì)象作為其屬性這其實(shí)反映了兩個(gè)類之間需要被映射的關(guān)系,Address 類本身也需要被映 射。重要的是這是一個(gè)遞歸的定義:在需要的地方,一個(gè)屬性將被映射到 0 個(gè)或者多個(gè)字段。最簡(jiǎn)單的映射就是把一個(gè)屬性映射到一個(gè)字段。當(dāng)雙方擁有一樣的基本類型的時(shí) 候,這甚至可以變得更簡(jiǎn)單。例如,雙方都是 date 類型,或者屬性是 string 類型
6、而字段是 char 型,或者屬性是 number 類型而字段是 float 類型。映射術(shù)語映射 (動(dòng)詞).指的是如何把對(duì)象和對(duì)象之間的關(guān)系持久化到永久存儲(chǔ)設(shè)備(這在里是關(guān)系型數(shù)據(jù)庫)中的行為。映射 (名詞).如何將對(duì)象的屬性或關(guān)系持久化到永久存儲(chǔ)設(shè)備的定義的關(guān)系。屬性. 數(shù)據(jù)屬性,是實(shí)際的物理屬性,例如一個(gè) firstName 字串;或者是由某個(gè)操作實(shí)現(xiàn)的虛擬屬性,例如 getTotal()方法返回一個(gè)訂單的總數(shù)。屬性映射. 描述如何持久化對(duì)象的屬性的映射。關(guān)系映射.描述如何持久化兩個(gè)或者更多的對(duì)象之間的一個(gè)關(guān)系(關(guān)聯(lián),聚合或者組合)。把類映射到表上會(huì)讓許多事情思考起來更簡(jiǎn)單,有時(shí)候的確是這樣
7、映射的,但并非總是這樣直接,除了少數(shù)特別簡(jiǎn)單的數(shù)據(jù)庫,你將不會(huì)有機(jī)會(huì)在類和表之間進(jìn) 行簡(jiǎn)單的一一映射。在這章的后面你將看到繼承映射。但是,就這一整章全面來 看,通常對(duì)于初始的映射,單類映射到單表是適用的(性能調(diào)優(yōu)可能會(huì)促使你對(duì)映射進(jìn)行重構(gòu))?,F(xiàn)在,讓我們從簡(jiǎn)單事物開始。圖 2 顯示了 2 個(gè)模型,一個(gè)UML的類圖和一個(gè)遵 循UML數(shù)據(jù)建模規(guī)則的物理數(shù)據(jù)模型。這兩張圖描繪了一個(gè)簡(jiǎn)單的訂單系統(tǒng)。你 可以看到如何映射類的屬性到數(shù)據(jù)庫的字段上。例如,圖里顯示Order類的 dateFulfilled屬性映射到Order表的dateFulfilled字段,OrderItem類的 numberOrdere
8、d屬性映射到OrderItem表的NumberOrdered字段。圖 2.簡(jiǎn)單映射的例子基本屬性的映射很容易確定,有幾個(gè)原因。首先,兩個(gè)模型中使用相似的命名規(guī) 則,這是采用敏捷建模實(shí)踐“建模標(biāo)準(zhǔn)化”的一個(gè)方面;其次,通常是同一群人 創(chuàng)建這兩個(gè)模型。而當(dāng)人們?cè)诓煌膱F(tuán)隊(duì)工作的時(shí)候,很容易做出不同的方案, 即便是在各個(gè)團(tuán)隊(duì)本身的工作都很出色的時(shí)候也是這樣,因?yàn)樗麄冄刂煌姆?向進(jìn)行決策;第三,一個(gè)模型很容易用來驅(qū)動(dòng)另一個(gè)模型的開發(fā)。在“不同的項(xiàng) 目需要不同策略”一文中我討論了當(dāng)你創(chuàng)建一個(gè)新系統(tǒng)的時(shí)候,你的對(duì)象schema 應(yīng)該主導(dǎo)你的數(shù)據(jù)庫schema的開發(fā)。圖 2 里面顯示的兩個(gè) schema
9、 雖然很相似,但還是存在一些區(qū)別。這些區(qū)別意味 著不存在一個(gè)完美的映射。2 個(gè) schema 間的不同點(diǎn)有:在對(duì)象 schema 里,tax 有多個(gè)屬性而數(shù)據(jù) schema 里只有一個(gè)。當(dāng)對(duì)象被保存時(shí), Order 類里 tax 的 3 個(gè)屬性將被相加并保存到 tax 字段里。然而,當(dāng)對(duì)象被讀進(jìn)內(nèi)存 時(shí),這 3 個(gè)屬性將需要被計(jì)算(或者使用一個(gè)延遲初始化的方式,這樣每個(gè)屬性僅 僅在第一次被訪問的時(shí)候計(jì)算)。一個(gè)像這樣的 schema 上的區(qū)別說明數(shù)據(jù)庫 schema 需要重構(gòu),把 tax 字段分成 3 個(gè)不同的字段。數(shù)據(jù)Schema標(biāo)明了鍵而對(duì)象Schema沒有。表中的每一行都有一個(gè)全表唯一的
10、主鍵 值,行間的關(guān)系被用外鍵實(shí)現(xiàn)。而對(duì)于對(duì)象之間的關(guān)系,是通過使用引用而非使用 外鍵。這暗示為了完整的持久化對(duì)象和它們的關(guān)系,對(duì)象需要知道數(shù)據(jù)庫里面用來 標(biāo)識(shí)它們的鍵值。這些額外的信息被稱為“shadow 信息”。每個(gè) Schema 里面使用了不同的類型。Order 里 subTotalBeforeTax 屬性是 Currency類型,而 Order 表里 subTotalBeforeTax 字段是 float 型。當(dāng)你實(shí)現(xiàn)這個(gè)映射,你需要 在這些數(shù)據(jù)的表示形式之間進(jìn)行無損轉(zhuǎn)換。2.1 Shadow 信息Shadow信息是指那些為了將對(duì)象持久化,而不得不維持的非業(yè)務(wù)數(shù)據(jù)。這通常 包括主鍵信息,
11、特別是當(dāng)主鍵是沒有業(yè)務(wù)含義的代理鍵值時(shí);并發(fā)控制標(biāo)識(shí)例如 時(shí)間戳或者增量計(jì)數(shù)器;以及那些版本號(hào)。例如,在圖 2 你可以看到Order表有 一個(gè)OrderID的字段作為主鍵,一個(gè)Order類所沒有的LastUpdate字段被用來樂觀 并發(fā)控制。為了正確持久化一個(gè)order對(duì)象,就需要實(shí)現(xiàn)包含這些信息的shadow 屬性。圖 3 顯示一個(gè)對(duì) Order 和 OrderItem 進(jìn)行詳細(xì)設(shè)計(jì)的類模型。和圖 2 相比,有一 些修改。首先,新的圖顯示了類需要正確持久化自己所需要的 shadow 屬性。 shadow 屬性是實(shí)現(xiàn)可見的,在它們的名字前面是一個(gè)空格而不是一個(gè)“”號(hào), 同時(shí)被指定了進(jìn)行說明(這
12、不是一個(gè) UML 標(biāo)準(zhǔn))。第二,它顯 示需要在兩個(gè)類之間實(shí)現(xiàn)聯(lián)系所需要的輔助(scaffolding)屬性。輔助屬性,例如 Order 里面的 orderItems 列表,同樣是實(shí)現(xiàn)可見的。第三,一個(gè) getTotalTax() 操作需要被加到 Order 類里來計(jì)算 Order 表中 tax 字段所需要的值。這是為什 么我用屬性映射這個(gè)詞來代替屬性映射你所想要做的是映射一個(gè)類里面的屬 性到數(shù)據(jù)庫里的字段上,有時(shí)這些屬性是通過簡(jiǎn)單的屬性實(shí)現(xiàn)的,而其它某些時(shí) 候是由一個(gè)或者多個(gè)操作所決定的。圖 3. 在一個(gè)類圖里包含shadow 信息我還沒有討論的一種 shadow 信息是用一個(gè) boolean
13、 類型的標(biāo)志來表示當(dāng)前一個(gè)對(duì)象是否存在于數(shù)據(jù)庫中。這里的問題是當(dāng)你把數(shù)據(jù)保存到一個(gè)關(guān)系型數(shù)據(jù)中, 如果原先的對(duì)象是從數(shù)據(jù)庫中獲取出來的,你需要使用一個(gè) SQL update 語句來 保存數(shù)據(jù),否則應(yīng)該使用 SQL insert 語句。一個(gè)普通的解決方法是為每個(gè)類實(shí) 現(xiàn)一個(gè) isPersistent 的 boolean 型信號(hào)標(biāo)志(圖 3 里沒有顯示),當(dāng)數(shù)據(jù)是從 數(shù)據(jù)庫里面讀取的時(shí)候把它的值設(shè)置成 true,如果對(duì)象是新創(chuàng)建的話則設(shè)置為false。在UML社區(qū)里面的一個(gè)通用的風(fēng)格約定是在類圖里不顯示shadow信息,例如鍵值 或并發(fā)標(biāo)識(shí)。類似的,通常也不顯示支撐代碼。因?yàn)槊總€(gè)人都知道你需要做這
14、種 事情,所以何必浪費(fèi)時(shí)間去顯示這些明顯的事實(shí)呢?Shadow信息不必用業(yè)務(wù)對(duì)象(business object)來實(shí)現(xiàn),不過那樣你的程序就 要在其他地方處理這個(gè)問題。例如,在Enterprise JavaBeans (EJBs)里你把主 鍵保存在EJB以外的主鍵類(primary key class)里,獨(dú)立對(duì)象引用相關(guān)的主鍵 對(duì)象。而進(jìn)一步的,Java Data Object(JDO)則是在JDOs里面實(shí)現(xiàn)shadow 信息, 而不是在業(yè)務(wù)對(duì)象(business object)里。2.2 映射元數(shù)據(jù)圖 4 顯示了元數(shù)據(jù)(meta data),這些是代表持久化圖 3 里Order和Order
15、Item 類所需要的屬性映射。元數(shù)據(jù)是關(guān)于數(shù)據(jù)的信息。因如下原因使得圖 4 顯得很重 要的。首先,我們需要某個(gè)方式來表現(xiàn)映射。我們可以把 2 個(gè)schema并排放在一 起,就像圖 2 里面那樣,然后在它們之間畫線,但是這很快會(huì)變的非常復(fù)雜,而 另外一個(gè)選擇是像圖 4 里面這樣列表;第二,映射元數(shù)據(jù)的概念對(duì)持久化框架的 功能是非常重要的,這是一個(gè)可以讓敏捷數(shù)據(jù)庫技術(shù)發(fā)揮作用的數(shù)據(jù)庫封裝策略。圖 4.代表屬性映射的元數(shù)據(jù)PropertyColumnOrder.orderIDOrder.OrderIDOrder.dateOrderedOrder.DateOrderedOrder.dateFulfil
16、ledOrder.DateFulfilledOrder.getTotalTax()Order.TaxOrder.subtotalBeforeTaxOrder.SubtotalBeforeTaxOrder.shipTo.personIDOrder.ShipToContactIDOrder.billTo.personIDOrder.BillToContactIDOrder.lastUpdateOrder.LastUpdateOrderItem.orderedOrderItem.OrderIDOrder.orderItems.position(orderItem)OrderItem.ItemSequ
17、enceOrderItem.item.numberOrderItem.ItemNoOrderItem.numberOrderedOrderItem.NumberOrderedOrderItem.lastUpdateOrderItem.LastUpdate我采用的命名規(guī)則是非常直接了當(dāng)?shù)模篛rder.dateOrdered 指得是 Order 類里的 dateOrdered 屬性。類似的還有,Order.DateOrdered 指得是 Order 表里的 DateOrdered 字段。Order.getTotalTax()指得是 Order 里的 getTotalTax() 操 作而 則是被 O
18、rder.billTo屬性引用的 Person 對(duì)象里 的 personID 屬性。看起來最難理解的屬性是 Order.orderItems.position(orderItem),它指向在將要保存的 OrderItem 實(shí)例里 Order.orderItems 列表中的位置。圖 4 暗示了面向?qū)ο蠹夹g(shù)和關(guān)系型技術(shù)之間一個(gè)最重要的阻抗失配。Class同時(shí) 實(shí)現(xiàn)行為和數(shù)據(jù),而關(guān)系型數(shù)據(jù)庫的表僅僅保存數(shù)據(jù)而已。這導(dǎo)致當(dāng)你映射一個(gè) 類的屬性到關(guān)系型數(shù)據(jù)庫時(shí),你也需要映射那些操作到數(shù)據(jù)庫字段上,例如: getTotalTax() 和position()。雖然在這個(gè)例子里面沒有出現(xiàn),但是你常常需要 映射
19、僅代表一個(gè)屬性兩個(gè)操作(operation)到一個(gè)字段一個(gè)操作是設(shè)置值 如:setFirstName(),而另外一個(gè)是獲取值,如getFirstName().這些操作通常 分別被稱作setter和getter,或者mutator和accessor.無論何時(shí),一個(gè)鍵值都要被映射到類里的一個(gè)屬性上,例如在 OrderItem.ItemSequence 和 Order.orderItems.position(orderItem)之間的 映射,這實(shí)際是關(guān)系映射的一部分工作,將在本章的后面進(jìn)行討論。這是因?yàn)樵?關(guān)系數(shù)據(jù)庫里通過使用鍵值來實(shí)現(xiàn)數(shù)據(jù)間的聯(lián)系。2.3 如何使映射適合全過程參看文章。3. 繼承結(jié)
20、構(gòu)的映射由于關(guān)系數(shù)據(jù)庫不是生來就支持繼承的,這就強(qiáng)制你必須將對(duì)象schema的繼承結(jié) 構(gòu)映射到相應(yīng)的數(shù)據(jù)庫schema中去。多半是因?yàn)椴焕慰康幕?譯注:不牢靠的 基類是指,有時(shí)基類很難修改,因?yàn)橐坏┬薷幕悾宇惥腿菀壮鲥e(cuò))的原因,面向?qū)ο笊鐓^(qū)不太提倡使用繼承,而我的經(jīng)驗(yàn)表明:之所以出現(xiàn)這個(gè)問題,是因 為面向?qū)ο蟮拈_發(fā)者們大多缺乏封裝的技巧,而非繼承概念本身出了問題(Ambler 2001a)。我想說的是,事實(shí)上,你只需要做少量的工作,即可將一個(gè)繼承層次映射到關(guān)系數(shù)據(jù)庫中去,而這并不會(huì)影響你在合適的地方運(yùn)用繼承。把對(duì)象存入關(guān)系數(shù)據(jù)庫時(shí),繼承的概念會(huì)帶來一些有趣的變化。如何在數(shù)據(jù)模型 中組織那
21、些通過繼承而得到的屬性?本節(jié)中,你將看到用來解決如何將繼承關(guān)系 映射到數(shù)據(jù)庫的三種基本方法,以及第四種補(bǔ)充方法,它不限于繼承映射。這些 方法如下所示:整個(gè)類層次結(jié)構(gòu)映射到一張表每個(gè)具體類單獨(dú)映射到一張表每個(gè)類單獨(dú)映射到一張表所有類映射到一個(gè)通用的表結(jié)構(gòu)如圖 6 所示,有兩個(gè)版本的類層次結(jié)構(gòu),我們將通過討論如何映射這兩個(gè)結(jié)構(gòu),來深入了解每種方法。第一個(gè)版本描述了三個(gè)類:一個(gè)抽象類 Person,和兩個(gè)具 體類 Employee 和 Customer。之所以知道 Person 是抽象類,是因?yàn)樵趫D中它用斜 體表示。在較早版本的 UML 中,會(huì)用約束“abstract”來表示抽象類。第二個(gè)版 本在第
22、一個(gè)版本的基礎(chǔ)上,往類層次結(jié)構(gòu)中添加了一個(gè)新的具體類 Executive。 旨在描述,當(dāng)實(shí)現(xiàn)了第一個(gè)類層次結(jié)構(gòu)之后,有了一個(gè)新的需求,要求為雇員中 的執(zhí)行主管,而非普通雇員,頒發(fā)固定的年度分紅。類 Executive 就是為了滿足這一新功能而添加的。簡(jiǎn)單起見,我沒有對(duì)這些類的所有屬性、屬性的完整簽名,以及類的任何操作進(jìn) 行建模。而這幅類圖恰好足以滿足我的目的,換句話說,這是一個(gè)敏捷的模型。 此外,這些類層次結(jié)構(gòu)本應(yīng)該用分析模式中的Party模式(Fowler 1997)或Business Entity模式(Ambler 1997)。我并沒有這么做,因?yàn)樵谶@里,我并不是為了說明 分析模式的有效應(yīng)
23、用,而是用一個(gè)簡(jiǎn)單的例子來說明繼承層次結(jié)構(gòu)的映射我 總是遵循敏捷建模(AM)的“每次只針對(duì)一個(gè)目標(biāo)建模”(Model With A Purpose) 的原則。圖 6. 一個(gè)簡(jiǎn)單類層次結(jié)構(gòu)的兩個(gè)版本誤用繼承也會(huì)帶來問題比如,圖 11.6 的層次結(jié)構(gòu)本應(yīng)該通過Party (Hay 1996, Fowler1997) 模式或Business Entity (Ambler 1997) 模式進(jìn)行更好的建模。舉例來說,有人可能既是 雇員又是顧客,為此你要在內(nèi)存中保留多個(gè)對(duì)象,而這可能會(huì)給你的應(yīng)用程序帶來問題。我 選擇這個(gè)例子,是因?yàn)槲倚枰粋€(gè)簡(jiǎn)單的,易于理解的類層次結(jié)構(gòu)來進(jìn)行映射。3.1 整個(gè)層次結(jié)構(gòu)映射
24、到一張表按照此策略,把所有類的所有屬性都存儲(chǔ)到一張表中去。當(dāng)采用這種方法時(shí),圖6 中的類層次結(jié)構(gòu)對(duì)應(yīng)的數(shù)據(jù)模型如圖 7 所示。這是非常直觀的方式,每個(gè)類的 屬性都存儲(chǔ)到表 Person 中,表名最好用類層次結(jié)構(gòu)中根類的名字來命名。圖 7. 映射到一張表表里多加了兩個(gè)字段PersonPOID 和 PersonType 。圖中,衍型(stereotype)說明第一個(gè)字段是表的主鍵,第二個(gè)字段是標(biāo)識(shí)代碼,用來指明一個(gè)人是 顧客還是雇員,抑或兩者皆是。PersonPOID是一個(gè)代理鍵(surrogate key), 它是持久化對(duì)象的標(biāo)識(shí)(POID,persistent object identifie
25、r),通常簡(jiǎn)稱為 對(duì)象標(biāo)識(shí)(OID,object identifier)。本應(yīng)該使用可選衍型(stereotype)來標(biāo)示的,但POID已經(jīng)暗示了這層意思,這表明,這類衍型(stereotype)只會(huì)無謂地使我們的類圖更復(fù)雜(參見AM實(shí)踐“簡(jiǎn)單地描述模型”(Depict Models Simply))。數(shù)據(jù)建模101( )詳細(xì)討論了 代理鍵(surrogate keys)的相關(guān)內(nèi)容。用來識(shí)別對(duì)象類型的字段PersonType是必需的,這個(gè)對(duì)象可以由給定的數(shù)據(jù)庫中 的一行數(shù)據(jù)實(shí)例化而來。例如,取值為E表示該人是雇員,C表示是顧客,B則表 示既是雇員又是顧客。這種方法看似直觀,但當(dāng)類型數(shù)目和類型間
26、聯(lián)合越來越多 的時(shí)候,這種方法就漸漸變的力不從心了。例如,添加執(zhí)行主管的概念,需要添 加一個(gè)碼值,比如以X來代表。對(duì)于值B來說,它代表的是既是雇員又是顧客,此 時(shí)就顯得有點(diǎn)不倫不類了。此外,有些(類間)聯(lián)合中可能會(huì)包括執(zhí)行主管,比 如,一個(gè)人既是執(zhí)行主管又是顧客也是很合乎情理的事情,這種情形也需要一個(gè) 碼值來表示。對(duì)于各種類型聯(lián)合的情況,應(yīng)該考慮使用“用布爾值來代替類型碼”(Replace Type Code With Booleans)的數(shù)據(jù)庫重構(gòu)技法,如圖8所示。為了簡(jiǎn)單,沒有包含那些需要并發(fā)控制的字段,比如位于圖 3 表中的時(shí)間戳字段, 同時(shí),用于數(shù)據(jù)版本跟蹤的字段也沒有包括在內(nèi)。圖 8
27、. 一種重構(gòu)方法3.2 每個(gè)具體類映射到單獨(dú)的一張表這種方法為每個(gè)具體類創(chuàng)建一張表,每張表既包括對(duì)應(yīng)類自己實(shí)現(xiàn)的那些屬性, 也包括它繼承下來的那些屬性。采用這種映射方法,圖 6 中的類層次結(jié)構(gòu)所對(duì)應(yīng) 的數(shù)據(jù)庫物理數(shù)據(jù)模型如圖 9 所示。每個(gè)具體類 Customer 和 Employee 都有對(duì) 應(yīng)的映射表,對(duì)象從這些表中被實(shí)例化,而抽象類 Person 則沒有對(duì)應(yīng)的表。分 別為每張表分配了對(duì)應(yīng)的主鍵,customerPOID 和 employeePOID。為了支持后加 的類 Executive,需要做的全部事情就是添加一張相應(yīng)的表,表中包括所有 Executive 對(duì)象所需要的屬性。圖 9.
28、把具體類映射成表3.3 每個(gè)類單獨(dú)映射到一張表遵循這個(gè)策略,為每個(gè)類創(chuàng)建一張表,每個(gè)業(yè)務(wù)屬性和任何必須的標(biāo)識(shí)信息都對(duì) 應(yīng)于表中的一個(gè)字段(還包括并發(fā)控制和版本跟蹤所需的其他字段)。將每個(gè)類 都映射成一張單獨(dú)的表,圖 6 中的類層次結(jié)構(gòu)對(duì)應(yīng)的物理數(shù)據(jù)模型如圖 10 所示。 類 Customer 的數(shù)據(jù)被存儲(chǔ)在兩張表 Customer 和 Person 中,因此要獲取這些數(shù) 據(jù),你需要連接這兩張表(或者分兩次讀取,每張表讀一次)。鍵的應(yīng)用很有意思。注意personPOID是如何作為所有表的主鍵來使用的。對(duì)于 Customer, Employee, 和 Executive 這些表而言,personP
29、OID既是主鍵又是 外鍵。對(duì)于Customer表,personPOID是它的主鍵,同時(shí)也作為外鍵來維系與表 Person之間的關(guān)聯(lián)。這是用 和 兩種衍型(stereotype)來表示的。 在一些較早版本的UML中,不允許為單個(gè)模型元素賦多個(gè)衍型(stereotype), 但在UML1.4 版中,取消了這一限制。圖 10. 每個(gè)類單獨(dú)映射一張表通常你可能會(huì)考慮的修改,是往表 Person 中添加一個(gè)類型字段或者布爾字段,用來表示 person 的可用子類。這個(gè)額外的花銷將使一些查詢變的更容易。在很 多情況下,添加額外的視圖(view)也是可行的選擇,我更傾向于這種方法,因?yàn)榕c附加類型或布爾字段相
30、比,這更易于維護(hù)。3.4 將類映射為一個(gè)通用的表結(jié)構(gòu)將繼承結(jié)構(gòu)映射到關(guān)系數(shù)據(jù)庫中去的第四種選擇是采用一種通用的,有時(shí)被稱為 元數(shù)據(jù)驅(qū)動(dòng)(meta-data driven)的方法來映射你的類,這種方法并不局限于繼 承結(jié)構(gòu),它支持所有形式的映射。圖 11 中所示的,是用于存儲(chǔ)屬性值和遍歷繼 承結(jié)構(gòu)的數(shù)據(jù) schema。這個(gè) schema 并不完全,例如它還可以被擴(kuò)展,用來映射 關(guān)聯(lián)關(guān)系,但對(duì)于我們的目的而言是足夠用了。單個(gè)屬性的值存放在 Value 表中, 因此,如果要保存一個(gè)帶有十個(gè)業(yè)務(wù)屬性的對(duì)象,那么需要十條記錄,每個(gè)屬性 對(duì)應(yīng)一條記錄。字段 Value.ObjectPOID 用來存儲(chǔ)特定對(duì)象
31、的唯一標(biāo)識(shí)(這種方法 假定對(duì)所有對(duì)象采用統(tǒng)一的鍵生成策略,假若不是這樣的話,你必須適當(dāng)?shù)臄U(kuò)展 這個(gè)表。) 表 AttributeType 包含了代表基本數(shù)據(jù)類型的記錄,如數(shù)據(jù),字符串,錢款,整數(shù)等等。將對(duì)象的屬性值轉(zhuǎn)換成為 varchar 類型保存到 Value.Value字段中時(shí),會(huì)需要這一信息。圖 11. 一個(gè)用于存儲(chǔ)對(duì)象的通用數(shù)據(jù) schema讓我們一起來看一個(gè)例子:將單個(gè)類映射到這種schema中。若要存儲(chǔ)圖 3 中的類OrderItem ,表Value中要有三條記錄,一條存儲(chǔ)已訂購的訂單項(xiàng)的數(shù)目,一條 存儲(chǔ)OrderPOID的值,該訂單項(xiàng)是相應(yīng)訂單的一部分,還有一條存儲(chǔ)ItemPOI
32、D 的 值,這個(gè)值用來描述訂單項(xiàng)。如果你采用樂觀鎖的方法進(jìn)行并發(fā)控制,你也可以 考慮用第四條記錄來儲(chǔ)存lastUpdated這個(gè)shadow屬性。表Class將為類 OrderItem 創(chuàng)建一行記錄,表Attribute將在數(shù)據(jù)庫中為每個(gè)屬性創(chuàng)建一行記錄(在本例子中,有三行或四行記錄)現(xiàn)在,將圖 6 所示的 Person 和 Customer 之間的繼承結(jié)構(gòu)映射到這種 schema 中。 表 Inheritance 是繼承映射的關(guān)鍵。每個(gè)類將由表 Class 中的一行來表示。在表 Inheritance 中也有一行,Inheritance.SuperClassPOID 的值指向表 Class
33、中表 示類 Person 的行,Inheritance.SubClassPOID 的值指向表中表示類 Customer 的行。映射剩余的結(jié)構(gòu)層次關(guān)系,需要在 Inheritance 表中為每個(gè)繼承關(guān)系都添 加一行。3.5 多重繼承映射到目前為止,我所關(guān)注的是單根繼承層次結(jié)構(gòu)的話題,所謂的單根繼承是指,子 類,如 Customer ,直接繼承單一的父類,如 Person 。多重繼承是指一個(gè)子類 有兩個(gè)或兩個(gè)以上的直接父類,如圖 12 所示,Dragon 直接繼承了類 Bird 和 Lizard 。在面向?qū)ο笳Z言中,多重繼承通常被認(rèn)為是有問題的,自 1990 年以來, 我只見過在一個(gè)領(lǐng)域問題中使用
34、多重繼承是有意義的,因此,多數(shù)語言不支持多 重繼承。但是像 C+和 Eiffel 這樣的語言支持多重繼承,所以也存在需要將多 重繼承層次結(jié)構(gòu)映射到關(guān)系數(shù)據(jù)庫中去的情況。圖 12 展示的是,對(duì)多重繼承分別使用三種繼承映射策略而得到的結(jié)果數(shù)據(jù) schema。如圖所示,多重繼承映射也是很簡(jiǎn)單的,跟單根繼承映射相比,并沒有 任何特別的東西。我所經(jīng)歷的最大挑戰(zhàn)是,當(dāng)將整個(gè)層次結(jié)構(gòu)映射到同一張表中 時(shí),如何為這張表取一個(gè)合理的名字,在本例中,用 Creature 最合適。圖 12. 映射多重繼承3.6 映射策略之間的比較如表 1 所示,就這些策略而言,沒有一種策略對(duì)所有場(chǎng)合都是理想的。我的經(jīng)驗(yàn) 表明,最容
35、易奏效的策略是,先用每個(gè)層次結(jié)構(gòu)映射一張表的策略,接下來如果 需要,就重構(gòu)相應(yīng)的 schema。有時(shí),當(dāng)我的團(tuán)隊(duì)被“純?cè)O(shè)計(jì)方法”的工作方式 所驅(qū)動(dòng),我會(huì)先采用每個(gè)類映射一張表的策略。我盡量不使用每個(gè)具體類映射一 張表的策略,因?yàn)檫@樣做最后導(dǎo)致的典型結(jié)果是,需要把數(shù)據(jù)在表之間拷來拷去 的,這就強(qiáng)制我在項(xiàng)目的初期就要對(duì)它進(jìn)行合理重構(gòu)。我很少使用通用 schema 方法,很簡(jiǎn)單,因?yàn)樗痪哂泻芎玫目缮炜s型。在任何應(yīng)用程序中,你都可以聯(lián)合使用前三個(gè)映射策略:每個(gè)層次結(jié)構(gòu)一個(gè)張表、 每個(gè)具體類一張表和每個(gè)類一張表, 理解這一點(diǎn)很重要。你甚至可以在一個(gè)大型 的層次結(jié)構(gòu)中聯(lián)合使用這三種策略。表 1.繼承映射
36、策略的比較Strategy策略Advantages優(yōu)勢(shì)Disadvantages缺陷When to Use使用的時(shí)機(jī)每個(gè)層次結(jié)構(gòu)一張表方法簡(jiǎn)單。添加新類很方便,你只需 要為新加的數(shù)據(jù)添加新 的字段即可。通過簡(jiǎn)單的修改行的“類 型”字段來實(shí)現(xiàn)多態(tài)。因?yàn)閿?shù)據(jù)在一張表中,因 此數(shù)據(jù)的訪問速度很快。因?yàn)樗械臄?shù)據(jù)在同一 張表中,特別容易生成專 門的報(bào)表。因?yàn)樗械念愔苯雨P(guān)聯(lián)到同一張表,類層次結(jié)構(gòu)內(nèi)的 耦合度增加。修改一個(gè)類將 影響整張表,而整張表的改 變又會(huì)影響類層次結(jié)構(gòu)中 的其他類。數(shù)據(jù)庫空間存在潛在浪費(fèi)。 如果已有類型之間有較大的重疊,則暗示著類型復(fù)雜 化了。對(duì)大的層次結(jié)構(gòu)而言,表會(huì) 非常大。對(duì)那
37、些類層次結(jié)構(gòu)內(nèi)部的類型間不存 在或存在極少重疊 情況的簡(jiǎn)單類層次 結(jié)構(gòu)和(或)繼承深 度比較淺的類層次 結(jié)構(gòu)而言,這種策略 很好每個(gè)具體類一張表由于單個(gè)類的所有數(shù)據(jù)都存儲(chǔ)在一張表中,所以 特別容易 生成專門的報(bào) 表。訪問單個(gè)對(duì)象數(shù)據(jù)的性 能高。類修改的時(shí)候必須修改它對(duì)應(yīng)的表,同時(shí)也必須修改 它所有的子類對(duì)應(yīng)的表。舉 例來說,如果你給類 Person 添加了 height 和 weight 兩 個(gè)屬性,那么你需要給表 Customer,Employee,和 Executive 添加對(duì)應(yīng)的字段。當(dāng)一個(gè)對(duì)象改變了它的角 色,比如,你雇用了你的顧 客,你需要把對(duì)象的數(shù)據(jù)復(fù) 制到相應(yīng)的表中,并為它分 配
38、一個(gè)新的 POID 值(或者 可以重用已有的 POID 值)。很難既支持多角色又能保 持?jǐn)?shù)據(jù)的完整性。比如,你 把既是顧客又是雇員的人 的名字存放到哪里?當(dāng)類型很少改變,類型之間極少重疊時(shí), 可以選擇使用這種 策略。每個(gè)類一張因?yàn)槭且灰粚?duì)應(yīng)的映射,每個(gè)類一張表,則在數(shù)據(jù)庫在類型之間有較大表所以容易理解。每個(gè)類型的記錄分別在 相應(yīng)的表中,因此可以很 好的支持多態(tài)。修改父類,或添加新的子 類時(shí),只需要簡(jiǎn)單的修改 或添加一張表。數(shù)據(jù)的大小跟對(duì)象個(gè)數(shù) 的增長成正比。中有很多表(還需要附加表用來維護(hù)類之間的關(guān)系)。使用這種方法,使得讀寫數(shù) 據(jù)需要更長的時(shí)間,因?yàn)樾?要訪問多張表。如果你明智 的組織你的數(shù)
39、據(jù)庫,把一個(gè) 類層次結(jié)構(gòu)中的每張表放 入不同的物理驅(qū)動(dòng)盤盤面 上(假設(shè)驅(qū)動(dòng)器磁頭的所有 操作相互獨(dú)立),就可以提 高數(shù)據(jù)的讀寫速度。從數(shù)據(jù)庫生成專門的報(bào)表 特別困難,除非添加視圖來 模擬所需要的表。重疊,或類型會(huì)頻繁的修改的情況下使 用這種策略。通用schema當(dāng)用一個(gè)穩(wěn)定的 持久化框架來封裝數(shù)據(jù)庫的訪 問,可以工作的非常好??梢詳U(kuò)展到提供元數(shù)據(jù), 以支持包括關(guān)系映射在 內(nèi)的更大范圍的映射。簡(jiǎn) 而言之,它是元數(shù)據(jù)映射 引擎的起點(diǎn)。非常靈活,可以快速的改 變存儲(chǔ)對(duì)象的方式,因?yàn)?只需要更新存儲(chǔ)在表 Class ,Inheritance , Attribute 和 AttributeType 中的
40、元數(shù)據(jù)。很先進(jìn)的技術(shù)最初可能難以實(shí)現(xiàn)。使用這種方法,需要訪問很 多數(shù)據(jù)庫的記錄來創(chuàng)建一 個(gè)對(duì)象,因此它只適用于少 量數(shù)據(jù)的情況。你可能需要一個(gè)小型的管 理程序來維護(hù)元數(shù)據(jù)。因?yàn)橐L問多行記錄來獲 取一個(gè)對(duì)象的數(shù)據(jù),因此, 用這種數(shù)據(jù)生成報(bào)表顯得 異常困難。適用于如下場(chǎng)合:處理少量數(shù)據(jù)的復(fù) 雜應(yīng)用程序;不常訪問數(shù)據(jù)的應(yīng) 用程序;可以預(yù)先將數(shù)據(jù)讀 入到緩存的應(yīng)用程 序。4.映射對(duì)象關(guān)系除了屬性映射與繼承映射,你還需要領(lǐng)會(huì)關(guān)系映射的藝術(shù)。有三種你需要進(jìn)行映 射的對(duì)象間關(guān)系:關(guān)聯(lián)、聚合以及組合。在這里,我將把這三種關(guān)系同等看待盡管涉及到引用完整性的時(shí)候,三者有些微妙差別,但他們的映射方式是一樣的。4.
41、1. 關(guān)系的類型在做映射時(shí),你需要關(guān)心兩類對(duì)象關(guān)系。第一類是基于多重性(multiplicity)的, 包含三種類型:一對(duì)一關(guān)系(One-to-one relationships)。這是一種兩端多重性(multiplicity)最大值都為1 的關(guān)系(譯注:兩端最多只有一個(gè)對(duì)象) 。舉個(gè)例子來說就像圖 13 中 Employee 與 Position 之間的擁有(holds)關(guān)系。每個(gè)雇員擁有且僅擁有一個(gè)職位,每個(gè)職位可能擁 有一個(gè)雇員(有些職位還可能空缺)。一對(duì)多關(guān)系 (One-to-many relationships) 。也 被稱作 多 對(duì)一關(guān) 系 (many-to-one relatio
42、nship),這種關(guān)系產(chǎn)生于一端多重性(multiplicity)最大為 1,而另一端大于 1 的 場(chǎng)合。例如 Employee 與 Division 之間的隸屬(work in)關(guān)系。每個(gè)雇員在一個(gè)部門工 作,任何給定部門都有一個(gè)或者多個(gè)雇員在里面工作。多對(duì)多關(guān)系(Many-to-many relationships)。這是一種兩端多重性(multiplicity)最大值 均大于 1 的關(guān)系。例如 Employee 與 Task 之間的 分派(assigned)關(guān)系。每個(gè)雇員可以被分派一個(gè)或多個(gè)任務(wù),每個(gè)任務(wù)可以被指派給 0 個(gè)或多個(gè)雇員。第二類是基于方向(directionality)的,
43、包含兩種類型:?jiǎn)蜗蜿P(guān)系和雙向關(guān)系。單向關(guān)系(Uni-directional relationships)。單向關(guān)系是指一個(gè)對(duì)象知道與其關(guān) 聯(lián)的其他對(duì)象,但是其他對(duì)象不知道該對(duì)象。例如,圖 13 中,Employee 和 Position 之間的擁有(holds)關(guān)系,圖中該關(guān)系是用帶開口箭頭的直線來表示的。Employee 對(duì)象知道其所擁有的職位,而 Position 對(duì)象不知道擁有它的雇員是誰(沒有需要知 道的必要)。不久你就會(huì)看到,單向關(guān)系要比雙向關(guān)系容易實(shí)現(xiàn)。雙向關(guān)系(Bi-directional relatinships)。雙向關(guān)系是指,關(guān)聯(lián)兩端的對(duì)象都彼 此知道對(duì)方。例如 Emplo
44、yee 與 Division 之間的隸屬(work in)關(guān)系。Employee 對(duì)象知道自己工作的部門,而 Division 對(duì)象也知道有哪些雇員在本部門工作。圖 13. 對(duì)象間的關(guān)系對(duì)象schema中有可能包含全部六種關(guān)系的組合。然而,關(guān)系技術(shù)并不支持單向關(guān)系的概念在關(guān)系數(shù)據(jù)庫中,所有的關(guān)聯(lián)都是雙向的,這也是對(duì)象技術(shù)與關(guān)系 技術(shù)之間阻抗失配(impedance mismatch)的一個(gè)方面。4.2.如何實(shí)現(xiàn)對(duì)象關(guān)系對(duì)象 schema 中的關(guān)系是通過對(duì)象的引用及操作來實(shí)現(xiàn)的。當(dāng)多重性 (multiplicity)是 1(比如 0.1 或者 1)的時(shí)候,這種關(guān)系通過一個(gè)對(duì)象引用、一 個(gè) get
45、ter 操作以及一個(gè) setter 操作來實(shí)現(xiàn)。舉例來說,圖 13 中,類 Employee 是通過組合 division 屬性、返回 division 屬性值的 getDivision()操作以及設(shè) 置 division 屬性值的 setDivision()操作來反映某個(gè)雇員隸屬于某一部門這個(gè) 事實(shí)的。用來實(shí)現(xiàn)對(duì)象關(guān)系的屬性和操作通常稱為輔助屬性和輔助操作。多重性(multiplicity)為“多”(比如 N,0.*,1.*)的關(guān)系是通過集合屬性 (collection attribute)(比如 Java 中的 Array 或者 HashSet),以及操縱該 集合的操作來實(shí)現(xiàn)的。例如,類
46、Division 定義了名叫 employees 的 HashSet 屬性、用來取值的 getEmployees()、用來設(shè)值的 setEmployees()、將一個(gè)雇員對(duì) 象 (employee)加入到 HashSet 的 addEmployee()以及從 HashSet 中刪除雇員對(duì) 象(employee)的 removeEmployee()。關(guān)系是單向的時(shí)候,只需要在“知道其它對(duì)象”的對(duì)象中實(shí)現(xiàn)代碼即可。比如 Employee 與 Position 間的單向關(guān)系,只需由類 Employee 來實(shí)現(xiàn)關(guān)聯(lián)。另一方 面,雙向關(guān)聯(lián)則需要兩個(gè)類都實(shí)現(xiàn)相關(guān)代碼,正如你在 Employee 與 Tas
47、k 之間的 多對(duì)多關(guān)系(many-to-many relationship)中看到的那樣。4.3.如何實(shí)現(xiàn)關(guān)系數(shù)據(jù)庫中的關(guān)系關(guān)系數(shù)據(jù)庫中,關(guān)系是通過使用外鍵(foreign key)來維護(hù)的。外鍵的值可能是 另一個(gè)表(某個(gè)行)鍵值的一部分,也可能就等于那個(gè)表(某個(gè)行)的鍵值。一 對(duì)一關(guān)系中需要其中一張表來定義外鍵。在圖 14 中你可以看到表 Position 包含 了 EmployeePOID,它是一個(gè)指向Employee 表的外鍵,用來實(shí)現(xiàn)兩者的關(guān)聯(lián)。換 種方式,在 Employee 表中定義 PositionPOID字段,也很簡(jiǎn)單。圖 14. 關(guān)系數(shù)據(jù)庫中的關(guān)系要實(shí)現(xiàn)一對(duì)多關(guān)系,你需要定義
48、一個(gè)從一表指向多表的外鍵(譯注:在one-to-many 關(guān)系中,UML 里所指的 one 和 many 和數(shù)據(jù)庫里的 multiplicity 是 反過來的。比如一個(gè) division 有幾個(gè) employee,UML 里認(rèn)為 division 是 one 端, 因?yàn)橐粋€(gè) division 對(duì)應(yīng)幾個(gè) employee;而數(shù)據(jù)庫 Entity-Relationship Diagram 里的 one 端指的是 employee,因?yàn)橐粋€(gè) employee 只會(huì)參與一個(gè)division-employee 關(guān)系,這個(gè)值就是所謂的 multiplicity)。 例如 Employee(多方)中就包含一
49、個(gè) DivisionPOID 字段(外鍵),用于實(shí)現(xiàn)與 Division(一方) 的隸屬(work in)關(guān)系(注:同時(shí),字段 DivisionPOID 在 Division 中是主鍵)。 你也可以選擇增設(shè)一個(gè)關(guān)聯(lián)表(associative table)來實(shí)現(xiàn)一對(duì)多關(guān)系(one-to-many relationship),從而很容易實(shí)現(xiàn)多對(duì)多關(guān)系(many-to-many)。在關(guān)系數(shù)據(jù)庫中,有兩種方式可以用來實(shí)現(xiàn)多對(duì)多關(guān)聯(lián)(many-to-many association)。第一種是在每個(gè)表中定義多個(gè)指向其他表的外鍵。比如要實(shí)現(xiàn) Employee 與 Task 之間的多對(duì)多關(guān)系,你可以在 Em
50、ployee 表中定義五個(gè) TaskPOID 字段,在 Task 表中定義七個(gè) EmployeePOID 字段。不過當(dāng)你想要賦予一個(gè)雇員超 過五項(xiàng)任務(wù),或者一項(xiàng)任務(wù)被分配給超過七個(gè)雇員時(shí),采用這種方法就會(huì)遇到麻 煩。更好的方式是實(shí)現(xiàn)一張被稱為的關(guān)聯(lián)表(associative table)的表。正如圖14 中的 EmployeeTask 所示,關(guān)聯(lián)表包含了與其相關(guān)聯(lián)的表的主鍵的組合。采用 這種方式,你可以將同一項(xiàng)任務(wù)分配給五十個(gè)人,或者給同一個(gè)人指派二十項(xiàng)任 務(wù),完全沒有問題。這個(gè)基本“技巧”的要點(diǎn)在于將多對(duì)多關(guān)系轉(zhuǎn)化為兩個(gè)一對(duì)多關(guān)系,它們都與同一個(gè)關(guān)聯(lián)表相關(guān)聯(lián)。因?yàn)橥怄I是用來連接表的,所以關(guān)系
51、型數(shù)據(jù)庫中的所有關(guān)系都是雙向的。這也就 是為什么你在哪張表中實(shí)現(xiàn)一對(duì)一關(guān)系都無所謂的原因,連接兩表的代碼相差無 幾。比如,圖 14 中,對(duì)于現(xiàn)有的 schema,連接兩者(Position 和 Employee) 之間的 holds 關(guān)系所使用的 SQL 代碼應(yīng)為SELECT * FROM Position, EmployeeWHERE Position.EmployeePOID = Employee.EmployeePOID假如在 Employee 表中實(shí)現(xiàn)外鍵,SQL 代碼應(yīng)為SELECT * FROM Position, EmployeeWHERE Position.PositionPO
52、ID = Employee.PositionPOID在數(shù)據(jù)庫中采用一致的鍵策略可以極大地簡(jiǎn)化進(jìn)行關(guān)系映射所需的努力。首先是盡可能使用單字段的鍵。然后是采用某種全局唯一的代理鍵(surrogate key), 可以遵從GUID或者HIGH-LOW生成策略。這樣的好處是你只需對(duì)同一種類型的鍵值列進(jìn)行映射。既然我們明白了如何分別在兩種技術(shù)(譯注:對(duì)象技術(shù)與關(guān)系數(shù)據(jù)庫技術(shù))中實(shí)現(xiàn) 關(guān)系,那么我們來看看怎么對(duì)它們做映射。我會(huì)從對(duì)象關(guān)系到關(guān)系數(shù)據(jù)庫映射的 角度來講解。記住一件事情,某些情況下你要做出設(shè)計(jì)決策。再之,謹(jǐn)防“神奇 的 CASE 工具欄按鈕”,不要幻想它們會(huì)為你包辦一切。4.4. 關(guān)系映射關(guān)系映
53、射的一條通用的經(jīng)驗(yàn)規(guī)則是你應(yīng)該使映射前后的多重性保持一致。因此一 對(duì)一的對(duì)象關(guān)系映射成一對(duì)一的數(shù)據(jù)關(guān)系,一對(duì)多的映射成一對(duì)多的,多對(duì)多的 映射成多對(duì)多的。不過世事無絕對(duì),你也可以將一對(duì)一關(guān)系映射成一對(duì)多甚至多 對(duì)多關(guān)系。這是因?yàn)橐粚?duì)一關(guān)系是一對(duì)多關(guān)系的子集,一對(duì)多關(guān)系也同樣是多對(duì) 多關(guān)系的子集。圖 15 描述了圖 13 的對(duì)象 schema 與圖 14 的數(shù)據(jù)庫 schema 之間的屬性映射。注 意我只需要映射對(duì)象的業(yè)務(wù)屬性和 shadow 信息,不需要映射像 Employee.position 和 Employee.tasks 之類的輔助屬性(scaffolding attribute)。這些輔助屬性是通過映 射到數(shù)據(jù)庫中的 shadow 信息來表示的。當(dāng)關(guān)系信息被讀入內(nèi)存,儲(chǔ)存于主鍵字 段中的值就會(huì)被解釋成對(duì)象中相應(yīng)的 shadow 屬性。與此同時(shí),通過為相關(guān)對(duì)象 的輔助屬性設(shè)置適當(dāng)?shù)娜≈?,主鍵字段所表達(dá)的關(guān)系也會(huì)被建立起來。圖 15. 屬性映射PropertyColumnPosition.titlePosition.TitlePosition.positionPOIDPosition.PositionPOIDEEmployee.NameEmployee.employeePOIDEmployee.EmployeePOI
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 鎮(zhèn)江市職工文體中心招聘真題2024
- 河南農(nóng)商銀行系統(tǒng)招聘真題2024
- 化學(xué)創(chuàng)新合作伙伴
- 2025至2030年中國燙發(fā)板市場(chǎng)分析及競(jìng)爭(zhēng)策略研究報(bào)告
- 2025至2030年中國標(biāo)準(zhǔn)型木工鋸片市場(chǎng)調(diào)查研究報(bào)告
- 2025至2030年中國提升機(jī)閘瓦間隙保護(hù)裝置市場(chǎng)調(diào)查研究報(bào)告
- 2025至2030年中國密封式自動(dòng)拋丸清理機(jī)數(shù)據(jù)監(jiān)測(cè)研究報(bào)告
- 2025━2030年中國熱軋帶助項(xiàng)目投資可行性研究報(bào)告
- 2025年油氣鉆采服務(wù)項(xiàng)目合作計(jì)劃書
- 2025年智能電子腰圍尺項(xiàng)目建議書
- 2024年浙江省中考社會(huì)試卷真題(含標(biāo)準(zhǔn)答案及評(píng)分標(biāo)準(zhǔn))
- 期末復(fù)習(xí)《《認(rèn)識(shí)100以內(nèi)的數(shù)》復(fù)習(xí)》(教案)2023-2024學(xué)年數(shù)學(xué)一年級(jí)下冊(cè)
- 2024年醫(yī)師定期考核必刷題庫附含參考答案
- 神經(jīng)外科護(hù)理病例討論-腦膜瘤課件
- NB/T 11434.5-2023煤礦膏體充填第5部分:膠凝材料技術(shù)要求
- 2024年租賃鏟車合同范本
- NB-T32036-2017光伏發(fā)電工程達(dá)標(biāo)投產(chǎn)驗(yàn)收規(guī)程
- 人才培養(yǎng)與團(tuán)隊(duì)建設(shè)計(jì)劃三篇
- 《客艙設(shè)備與服務(wù)》課件-1.客艙乘務(wù)員
- 100以內(nèi)進(jìn)退位加減法口算題每天60道
- 小兒推拿健康檔案表
評(píng)論
0/150
提交評(píng)論