Entity Framework 4 in Action读书笔记——第一章:数据访问重载:Entity Framework(2)...
上一篇講解了通用數(shù)據(jù)容器,這一篇使用類來(lái)組織數(shù)據(jù)。
類是面向?qū)ο缶幊陶Z(yǔ)言的基礎(chǔ)。使用類,你不需要知道具體的存儲(chǔ)機(jī)制,數(shù)據(jù)源可以是數(shù)據(jù)庫(kù),Web服務(wù),XML文件等。類提供了很多優(yōu)勢(shì),尤其是在企業(yè)應(yīng)用中。
1.強(qiáng)類型 2.編譯時(shí)檢查 3.易于開(kāi)發(fā) 4.存儲(chǔ)無(wú)關(guān)
使用類展示數(shù)據(jù)
我們重新從零開(kāi)始。你的客戶想要在表格中展示所有的訂單,第一步就是要新建一個(gè)Order類容納訂單數(shù)據(jù),如下圖所示:
第二步再新建一個(gè)類,這個(gè)類包含一個(gè)從數(shù)據(jù)庫(kù)中讀取數(shù)據(jù)的方法,并將數(shù)據(jù)轉(zhuǎn)換成對(duì)象。這個(gè)容器類通常放在一個(gè)單獨(dú)的程序集里,就是所謂數(shù)據(jù)層。方法代碼如下:
訂單的集合看到這段代碼,很多人的第一反應(yīng)是,怎么這么多代碼啊?不過(guò)沒(méi)關(guān)系,當(dāng)事情變得復(fù)雜的時(shí)候,類就會(huì)給我們提供更多的幫助了。
從單個(gè)類到對(duì)象模型
你已經(jīng)看到怎樣創(chuàng)建一個(gè)單獨(dú)的類以及用數(shù)據(jù)庫(kù)中的數(shù)據(jù)初始化它。但是它真正強(qiáng)大的地方是創(chuàng)建多個(gè)類并將它們彼此聯(lián)系起來(lái)。在數(shù)據(jù)庫(kù)中,Order和OrderDetail之間的關(guān)系被描述為Order表中OrderId列和OrderTable中OrderId列的外鍵約束。從數(shù)據(jù)庫(kù)設(shè)計(jì)的角度,這是正確的方法。但是在面向?qū)ο蟮氖澜缰?#xff0c;這是行不通的。我們創(chuàng)建一個(gè)OrderDetail類并給它一個(gè)OrderId屬性這是沒(méi)有意義的。最好的解決方案就是運(yùn)用類的獨(dú)特性:類的屬性類型可以是用戶自定義的類。也就是說(shuō),在Order類中可以引用OrderDetail對(duì)象的集合,OrderDetail可以引用Order對(duì)象。當(dāng)創(chuàng)建了這些關(guān)系,也就開(kāi)始創(chuàng)建對(duì)象模型了。
關(guān)系和對(duì)象的不同
了解面向?qū)ο蠛完P(guān)系的區(qū)別很重要,因?yàn)樗绊懼鴮?duì)象模型或者領(lǐng)域模型和數(shù)據(jù)庫(kù)的設(shè)計(jì)。
下面就從幾個(gè)方面講述它們的不匹配。
1、數(shù)據(jù)類型(datatype)
(1).當(dāng)往數(shù)據(jù)庫(kù)表中添加一列時(shí),必須確定它的類型。現(xiàn)代數(shù)據(jù)庫(kù)支持的類型有char, varchar, int, decimal, date等等。但是涉及到類就同了,數(shù)據(jù)庫(kù)中的int和bigint類型可以跟.NET中的Int32和Int64類型匹配,但是數(shù)據(jù)庫(kù)其他類型就沒(méi)有跟.NET中類型有確切的匹配了。
(2).在數(shù)據(jù)庫(kù)中可以設(shè)置約束條件,比如說(shuō)給nvarchar類型的數(shù)據(jù)設(shè)置一個(gè)最大長(zhǎng)度。但是在.NET中沒(méi)有nvarchar類型,與此類型相近的就是String類型,如果想設(shè)置最大長(zhǎng)度只能在屬性中或者方法中設(shè)定然后再存儲(chǔ)到數(shù)據(jù)庫(kù)中。
(3).數(shù)據(jù)庫(kù)可以接受二進(jìn)制數(shù)據(jù),但是二進(jìn)制列不知道這些數(shù)據(jù)代表什么,可能是一個(gè)文本文檔、PDF文件或者圖片。在.NET中可以用Object表示這一列,但是沒(méi)有意義,因?yàn)槟忝鞔_的知道在二進(jìn)制列中存儲(chǔ)的是什么類型的數(shù)據(jù)。如果存儲(chǔ)的是一個(gè)文件,可以用Stream屬性,如果是圖片,那么Images類型是你最佳選擇。
(4).在SQL Server2005中有DateTime和Small-DateTime,SQL Server2008中新增了Date 和 Time兩個(gè)類型。如你所想,第一個(gè)只存儲(chǔ)日期,第二個(gè)只存儲(chǔ)時(shí)間。在.NET中只有一個(gè)DateTime類來(lái)表示日期和時(shí)間。
2、關(guān)聯(lián)(association)
談到關(guān)聯(lián),最大的不匹配就是關(guān)系世界和對(duì)象世界中的關(guān)系是怎樣維持的。
(1).一對(duì)一關(guān)系
如果往Order表中加入其他列,這起初看似是一個(gè)小的改動(dòng),不會(huì)有太大危險(xiǎn),但是事實(shí)并非如此,因?yàn)楹芏喑绦蚨家玫竭@個(gè)表。替代方法是新建一個(gè)表,用OrderId作為主鍵,在這個(gè)表中加入新增的列。數(shù)據(jù)庫(kù)中這是一個(gè)合理的權(quán)衡辦法,如果在對(duì)象模型中也這么做,那就沒(méi)有意義了。最好的方法就是在Order類中添加一個(gè)屬性。如下圖所示:
(2).一對(duì)多關(guān)系
在數(shù)據(jù)庫(kù)中表示“多”一方的表包含父表中的主鍵。例如,在OrderDetail表中包含一個(gè)連接到Order的OrderId列,數(shù)據(jù)庫(kù)術(shù)語(yǔ)稱為外鍵。從本質(zhì)上講,數(shù)據(jù)庫(kù)表的關(guān)聯(lián)既是單一的又是雙向的。單一的是指只需在OrderDetail一方定義關(guān)系,在Order表上不需定義任何東西。雙向是指即使你只修改一方,也會(huì)影響到另一方。這是可能的,因?yàn)镾QL允許你在數(shù)據(jù)表間執(zhí)行聯(lián)合查詢。
在面向?qū)ο笫澜缰?#xff0c;不存在這種機(jī)制,因?yàn)槊繕訓(xùn)|西都是明確聲明的。OrderDetail類通過(guò)Order屬性到Order的引用,這一點(diǎn)有點(diǎn)像數(shù)據(jù)庫(kù)。實(shí)際的不同你也必須修改Order類,添加一個(gè)包含OrderDetail對(duì)象集合的OrderDetails屬性。這種關(guān)系如下圖所示:
(3).多對(duì)多關(guān)系
多對(duì)多關(guān)系中,表與表之間的關(guān)系沒(méi)有主次之分。例如你有Product和Supplier表,你不能簡(jiǎn)單的在一個(gè)表上創(chuàng)建外鍵表示它們的關(guān)系。Product和Supplier表只包含它們自己的數(shù)據(jù),這樣一來(lái),兩個(gè)表不能直接相連,需要依靠第三個(gè)表。
在對(duì)象模型中的做法是創(chuàng)建Product和Supplier兩個(gè)類。在Product類中添加一個(gè)包含Supplier對(duì)象集合的Suppliers屬性,同樣,在Supplier類中添加一個(gè)包含Product對(duì)象集合的Products屬性。如圖所示:
3、顆粒度(granularity)
granularity在這里不知道怎么翻譯比較合適,暫且翻譯成顆粒度吧。顆粒度問(wèn)題指的是類的個(gè)數(shù)和數(shù)據(jù)庫(kù)中表的個(gè)數(shù)不一致。一對(duì)一關(guān)系中,有兩個(gè)表Order和Order2,但是只有一個(gè)Order類。還是讓我們看例子吧。
在Order表中有一個(gè)送貨地址,被分成了4列:address,city,zip code和country。如果你還要處理其他地址,比如賬單地址,你還要在Order表中添加4列。如圖所示:
在Order類中已經(jīng)送貨地址的四個(gè)屬性,所以再添加四個(gè)也不會(huì)有問(wèn)題,盡管它工作的很順利,這些屬性會(huì)使類變得越來(lái)越大,越來(lái)越難懂。更重要的是,customers和suppliers表中有地址,或者其他還有地址。類可以重用,創(chuàng)建一個(gè)AddressInfo類,然后重用它不是更好嗎?下面是重構(gòu)完的代碼:
AddressInfo類和Order類4、繼承(inheritance)
繼承不匹配指的是在數(shù)據(jù)庫(kù)中實(shí)現(xiàn)繼承是不可能的。我們添加一個(gè)Customer類來(lái)完善對(duì)象模型,然后讓Customer和Supplier類都繼承自Company。在關(guān)系型數(shù)據(jù)庫(kù)中你不能簡(jiǎn)單的聲明Customer表繼承自另一個(gè)表。你可以創(chuàng)建一個(gè)包含Customer和Supplier數(shù)據(jù)的表或者是單獨(dú)創(chuàng)建。不管選擇哪種方式,在數(shù)據(jù)庫(kù)和對(duì)象模型都存在不匹配的問(wèn)題。
在對(duì)象模型中,有一個(gè)Product類。一個(gè)商店各種各樣的產(chǎn)品,如鞋子,襯衫,高爾夫設(shè)備,有用設(shè)備等等。這些東西都有一些共有的屬性,如價(jià)格和顏色等。即使在這樣一個(gè)例子中,繼承也會(huì)對(duì)你有所幫助。現(xiàn)在創(chuàng)建一個(gè)Product類,然后為每一個(gè)具體的產(chǎn)品創(chuàng)建類。但是當(dāng)你設(shè)計(jì)OrderDetail類的時(shí)候問(wèn)題出現(xiàn)了,在OrderDetail類中,需要一個(gè)屬性指定是哪個(gè)產(chǎn)品的訂單詳細(xì)信息。即使在運(yùn)行時(shí),這個(gè)屬性的類型都是Product,具體對(duì)象的實(shí)例可能是鞋子,襯衫或者任何繼承自Product類型的產(chǎn)品。如圖所示:
這種類型的結(jié)構(gòu)稱為多態(tài),在數(shù)據(jù)庫(kù)中是不可能表示的。
5、標(biāo)識(shí)(identity)
數(shù)據(jù)庫(kù)表中標(biāo)識(shí)一行的是主鍵,因此你為一個(gè)表選擇主鍵時(shí)一定要注意。有時(shí)候你可能想使用自然鍵(natural key),比如產(chǎn)品的代碼,但是這種選擇有可能帶來(lái)麻煩。假如你要修改產(chǎn)品的代碼,因?yàn)槟爿斿e(cuò)了。但是產(chǎn)品代碼在OrderDetail表中是外鍵,所以你必須更新OrderDetail表中的產(chǎn)品代碼。問(wèn)題是你不能更新OrderDetail表中的產(chǎn)品代碼,因?yàn)槿绻阈薷牡闹翟赑roduct表中不存在就會(huì)出現(xiàn)錯(cuò)誤。另一方面,你不能修改Product表中的值,因?yàn)檫`反了外鍵約束。
這看起來(lái)是最惱人的問(wèn)題了,但是還有一個(gè)原因要避免使用自然鍵。產(chǎn)品代碼可能是比較長(zhǎng)的字符串,但是幾乎所有的數(shù)據(jù)庫(kù)都為存儲(chǔ)和搜索整數(shù)值做了優(yōu)化,所以最有效的主鍵是代理鍵(surrogate key)。代理鍵的使用可以允許你修改其他任何列的值而不用擔(dān)心影響到其他表。
到目前為止,我們已經(jīng)說(shuō)明了一個(gè)對(duì)象就是表中一行的面向?qū)ο蟊硎?#xff0c;主鍵屬性將對(duì)象和行聯(lián)系起來(lái)。問(wèn)題是,如果比較兩個(gè)相同類型的不同對(duì)象,即時(shí)它們包含了相同的數(shù)據(jù)也證明是不相同的。為什么包含相同數(shù)據(jù)的對(duì)象是不同的呢?因?yàn)槟J(rèn)情況下指向表示數(shù)據(jù)庫(kù)表中同一行數(shù)據(jù)的不同對(duì)象的兩個(gè)變量是不同的。如果兩個(gè)變量指向相同的實(shí)例,那么它們是相等的,這被稱之為“引用相等”。如果有一個(gè)方法可以改變這種默認(rèn)行為,肯定是更可取的。如果兩個(gè)不同的對(duì)象包含相同的數(shù)據(jù),那么它們比較的結(jié)果應(yīng)該返回True。在.NET中,可以重寫Equals和GetHashCode方法到達(dá)同等的效果。
寫在最后的話
在前面,我們看到了關(guān)系世界和對(duì)象世界之間存在這么多的不同,下一篇將就這些不同給出解決方案。
轉(zhuǎn)載于:https://www.cnblogs.com/nianming/archive/2011/08/12/2136508.html
總結(jié)
以上是生活随笔為你收集整理的Entity Framework 4 in Action读书笔记——第一章:数据访问重载:Entity Framework(2)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: T420s成功加装固态硬盘(SSD)
- 下一篇: 《道德经》程序员版第五章