Android資料庫高手祕籍(4):使用LitePal建立表關聯

發表於2015-09-04

目前我們已經對LitePal的用法有了一定了解,學會了使用LitePal來建立表和升級表的方式,那麼今天就讓我們一起繼續進階,探究一下如何使用LitePal來建立表與表之間的關聯關係。還沒有看過前一篇文章的朋友建議先去參考Android資料庫高手祕籍(3):使用LitePal升級表 

LitePal的專案地址是:https://github.com/LitePalFramework/LitePal

關聯關係的基礎知識

喜歡把所有的程式碼都寫在一個類裡的程式設計師肯定是個新手。沒錯,任何一個像樣的程式都不可能僅僅只有一個類的,同樣地,任何一個像樣的資料庫也不可能僅僅只有一張表。我們都知道,在物件導向的程式語言中,多個類之間可以相互關聯引用,共同完成某項功能。那麼在資料庫當中,多個表之間可以相互關聯嗎?當然可以!只不過表與表之間的關聯關係要比物件之間的關聯關係複雜一些,也更加難懂,但是作為資料庫的基本功,還是應該瞭解清楚的,那麼我們就先來學習一下資料庫表關聯的基礎知識。

表與表之間的關聯關係一共有三種型別,一對一、多對一、和多對多,下面我們分別對這三種型別展開進行討論。

一對一

表示兩個表中的資料必須是一一對應的關係。這種場景其實並不是很常見,我們還是通過例子來直觀地體會一下,例子仍然是在之前文章的基礎上展開的。

現在我們已經建立好了news這張表,裡面主要記錄了新聞的標題和內容,那麼除了標題和內容之外,有些新聞還可能帶有一些導語和摘要,我們把這兩個欄位放在一張introduction表中,作為新聞的簡介。那麼很顯然,news表和introduction表就是一對一的關係了,因為一條新聞只能對應一個簡介,一個簡介也只能屬於一條新聞。它們之間的對應關係大概如下圖描述的一樣:

20140921142813365

可以看到,News1對應了Introduction2,News2對應了Introduction3,News3對應了Introduction1,但不管怎麼樣,它們都是一對一的關係。

那麼這種一對一的關係,在程式語言中該怎麼體現出來呢?相信熟悉物件導向設計的你,一定很輕鬆就能想出來吧,只需要在News類中持有一個Introduction類的引用,然後在Introduction類中也持有一個News類的引用,這樣它們之間自然就是一對一的關係了。

沒錯,物件之間的一對一關係非常簡單易懂,那麼難點就在於,如何在資料庫表中建立這樣的一對一關係了。由於資料庫並不像物件導向的語言一樣支援相互引用,如果想讓兩張表之間建立一對一的關係,一般就只能通過外來鍵的方式來實現了。因此,一對一關係的表結構就可以這樣設計:

20140921150720921

請注意,introduction表中有一個news_id列,這是一個外來鍵列,裡面應該存放一個具體的新聞id,這樣一條introduction就能對應一條news,也就實現一對一的關係了,如下圖所示:

20140921153252093

由此我們就能夠看出,id為1的introduction對應著id為2的news,id為2的introduction對應著id為3的news,id為3的introduction對應著id為1的news。需要注意的是,一對一的關係並沒有強制要求外來鍵必須加在哪一張表上,你可以在introduction表中加一個news_id作為外來鍵,也可以在news表中加一個introduction_id作為外來鍵,不管使用哪一種,都可以表示出它們是一對一的關聯關係。

多對一

表示一張表中的資料可以對應另一張表中的多條資料。這種場景比起一對一關係就要常見太多了,在我們平時的開發工作中多對一關係真的是比比皆是。比如說現在我們的資料庫中有一個news表,還有一個comment表,它們兩個之間就是典型的多對一關係,一條新聞可以有很多條評論,但是一條評論只能是屬於一條新聞的。它們的關係如下圖所示:

20140921161557859

而這種多對一的關係在程式語言中是非常容易體現出來的,比如Java中就有專門集合類,如List、Set等,使用它們的話就能輕鬆簡單地在物件之間建立多對一的關係,我們稍後就會看到。那麼,這裡的難點仍然是在資料庫表中如何建立這樣的多對一關係。現在說難點其實已經不難了,因為前面我們已經學會了一對一關係的建立方法,而多對一也是類似的。沒錯,資料庫表中多對一的關係仍然是通過外來鍵來建立的,只不過一對一的時候外來鍵加在哪一張表上都可以,但多對一的時候關鍵必須要加在多方的表中。因此,多對一關係的表結構就可以這樣設計:

20140921164633281

在comment表中有一個news_id列,這是一個外來鍵列,裡面應該存放一個具體的新聞id,並且允許多條comment都存放同一個新聞id,這樣一條評論就只能對應一條新聞,但一條新聞卻可以有多條評論,也就實現多對一的關係了,如下圖所示:

20140921165820421

由此我們就可以看出,id為1、2、3的三條評論是屬於第一條新聞的,而id為4、5的兩條評論是屬於第二條新聞的。

多對多

表示兩張關聯表中的資料都可以對應另一張表中的多條資料。這種場景也不算是很常見,但比一對一關係要稍微更加常用一些。舉個例子,我們都知道新聞網站是會將新聞進行種類劃分的,這樣使用者就可以選擇自己喜歡的那一類新聞進行瀏覽,比如說網易新聞中就會有頭條、科技、娛樂、手機等等種類。每個種類下面當然都會有許多條新聞,而一條新聞也可能是屬於多個種類的,比如iPhone6釋出的新聞既可以屬於手機種類,也可以屬於科技種類,甚至還可以上頭條。因此,新聞和種類之間就是一種多對多的關係,如下圖所示:

20140921180813796

可以看到,News1是屬於Category1的,而News2和News3都是既屬於Category1也屬於Category2,如此複雜的關聯關係該如何表示呢?在物件導向的程式語言中一切都是那麼的簡單,只需要在News類中使用集合類宣告擁有多個Category,然後在Category類中也使用集合類宣告擁有多個News就可以了,我們稍後就會看到。而難點仍然是留在了資料庫上,兩張表之間如何建立多對多的關聯關係呢,還是用外來鍵嗎?肯定不行了,多對多的情況只能是藉助中間表來完成了。也就是說,我們需要多建立一張表,這張表沒什麼其它作用,就是為了存放news表和category表之間的關聯關係的,如下圖所示:

20140921182934687

注意這裡我們建立一張名為category_news的中間表,中間表的命名並沒有什麼強制性的約束,但一個良好的命名規範可以讓你一眼就明白這張表是用來做什麼的。中間表裡面只有兩列,而且也只需要有兩列,分別是news表的外來鍵和category表的外來鍵,在這裡存放新聞和種類相應的id,就可以讓它們之間建立關聯關係了,如下圖所示:

20140921185255046

由此我們就可以看出,第一條新聞是屬於第一個種類的,而第二和第三條新聞,則既屬於第一個種類,也屬於第二個種類。反過來也可以這樣看,第一個種類下面有第一、第二、第三這三條新聞,而第二個種類下面只有第二、第三這兩條新聞。不管怎麼看,多對多的關係都是成立的。

好了,三種關聯關係都講完了,那我們來簡單總結一下吧。雖說上面介紹了花了很大的篇幅講解資料庫的表關聯知識,但其實最後的結論是非常簡單的,大家可以當成口訣一樣背下來。即一對一關聯的實現方式是用外來鍵,多對一關聯的實現方式也是用外來鍵,多對多關聯的實現方式是用中間表。記下了這個口訣,在很多資料庫設計的時候,你都可以發揮得更加遊刃有餘。

使用LitePal建立表關聯

雖說口訣就是這個樣子,但牽扯到表關聯的時候畢竟增加了建表的難度,建表語句會更加複雜,你也需要格外地小心以防止出現什麼錯誤。因此,使用LitePal來自動建立表關聯又是一個非常不錯的選擇,我們不需要關心什麼外來鍵、中間表等實現的細節,只需要在物件中宣告好它們相互之間的引用關係,LitePal就會自動在資料庫表之間建立好相應的關聯關係了,下面我們就來嘗試一下吧。

首先確定一下一共涉及到了哪些實體類,News和Comment,這兩個類我們在前兩篇文章中就已經建好了,然後還需要有Introduction和Category這兩個類,新建Introduction類,程式碼如下所示:

接著新建Category類,程式碼如下所示:

現在四個類都已經建好了,但目前它們都還是各自獨立的,互相之間沒有任何聯絡,那麼我們現在就開始用極為簡單易懂的方式來給它們建立關聯吧。首先,News和Introduction是一對一的關係,那就可以在News類中新增如下引用:

就是這麼簡單,在News類中可以得到一個對應的Introduction的例項,那麼它們之間就是一對一關係了。

接著Comment和News是多對一的關係,因此News中應該包含多個Comment,而Comment中應該只有一個News,所以就可以這樣寫:

先使用一個泛型為Comment的List集合來表示News中包含多個Comment,然後修改Comment類的程式碼,如下所示:

在Comment類中宣告瞭一個News的例項,這樣就清楚地表示出了News中可以包含多個Comment,而Comment中只能有一個News,也就是多對一的關係了。

最後News和Category是多對多的關係,相信聰明的你一定已經知道該怎麼寫了。News中可以包含多個Category,所以仍然應該使用List集合來表示:

而Category中也可以包含多個News,因此Category類也應該使用相同的寫法,如下所示:

這樣就清楚地表達出它們之間是多對多的關聯了。
關聯關係都宣告好了之後,我們只需要將所有的實體類都新增到對映列表當中,並將資料庫版本號加1就可以了。修改litepal.xml的程式碼,如下所示:

 

基本上到這裡就可以輕鬆地說結束了,現在只需要任意操作一下資料庫,表之間的關聯關係就將會自動建立,比如說呼叫一下Connector.getDatabase()方法。

下面我們來驗證一下吧,輸入.table命令檢視一下當前資料庫中的表,如下所示:

20140921221142359

OK,news、comment、category、introduction這幾張表全都有了,除此之外還有一張category_news中間表。那我們要來一一檢查一下了,先檢視一下introduction表的結構吧,如下所示:

20140921221755906

可以看到,多了一個news_id列,說明introduction表和news表之間的一對一關係已經建立好了。

然後再檢查一下comment表的結構,如下所示:

20140921222136007

OK,comment表中也有一個news_id的列,那麼comment表和news表之間的多對一關係也已經建立好了。

最後檢查一下category_news這張中間表的結構,如下所示:

20140921222343194

一共只有兩列,一列是news_id,一列是category_id,分別對應著兩張表的外來鍵,這樣news表和category表的多對多關係也建立好了。

藉助LitePal的幫助,即使你並不熟悉資料庫的表關聯設計,只要你會物件導向程式設計,都可以輕鬆地將表與表之間的關聯建立起來。建立表、升級表、表關聯,這就是LitePal在資料庫表管理方面給我們帶來的巨大便利,相信大家都能體會到它的魅力所在了。那麼到這裡為止,我們就把使用LitePal進行表管理的知識全部學完了,從下一篇文章開始,我將會講解如何使用LitePal進行CRUD的操作。感興趣的朋友請繼續閱讀 Android資料庫高手祕籍(5):LitePal的儲存操作 。

 

LitePal開源專案地址:https://github.com/LitePalFramework/LitePal

相關文章