Android數(shù)據(jù)庫(kù)操作(二)——建表怎囚、升級(jí)表卿叽、表關(guān)聯(lián)

前言

本文參考轉(zhuǎn)發(fā)摘自:郭霖博客http://blog.csdn.net/guolin_blog?viewmode=contents 強(qiáng)烈建議進(jìn)入原博客查看學(xué)習(xí)

1、建表

  • 操作數(shù)據(jù)庫(kù)的第一步當(dāng)然是創(chuàng)建表了恳守,傳統(tǒng)創(chuàng)建表的方法相信大多數(shù)人都知道考婴,那么今天我除了會(huì)展示傳統(tǒng)的建表方法之外,還會(huì)講解LitePal這個(gè)框架的基本用法催烘,并使用它來(lái)完成同樣的建表操作沥阱,讓大家體會(huì)到使用框架來(lái)操作數(shù)據(jù)庫(kù)的魅力。
  • 那么先來(lái)簡(jiǎn)單介紹一下吧伊群,LitePal是一款開(kāi)源的Android數(shù)據(jù)庫(kù)框架考杉,它采用了對(duì)象關(guān)系映射(ORM)的模式,并將我們平時(shí)開(kāi)發(fā)時(shí)最常用到的一些數(shù)據(jù)庫(kù)功能進(jìn)行了封裝舰始,使得不用編寫(xiě)一行SQL語(yǔ)句就可以完成各種建表崇棠、増刪改查的操作。并且LitePal很“輕”蔽午,jar包只有100k不到易茬,而且近乎零配置,這一點(diǎn)和hibernate這類(lèi)的框架有很大區(qū)別。目前LitePal的源碼已經(jīng)托管到了GitHub上抽莱,地址是https://github.com/LitePalFramework/LitePal 范抓。

1.1 傳統(tǒng)的建表方式

  • 為了方便我們對(duì)數(shù)據(jù)庫(kù)表進(jìn)行管理,Android本身就提供了一個(gè)幫助類(lèi): SQLiteOpenHelper食铐。這個(gè)類(lèi)集創(chuàng)建和升級(jí)數(shù)據(jù)庫(kù)于一身匕垫,并且自動(dòng)管理了數(shù)據(jù)庫(kù)版本,算是一個(gè)非常好用的工具虐呻。

  • 那我們現(xiàn)在就來(lái)試試 SQLiteOpenHelper 的用法吧象泵。首先你要知道 SQLiteOpenHelper是一個(gè)抽象類(lèi),這意味著如果我們想要使用它的話斟叼,就需要?jiǎng)?chuàng)建一個(gè)自己的幫助類(lèi)去繼承它偶惠。SQLiteOpenHelper中有兩個(gè)抽象方法,分別是 onCreate()onUpgrade() 朗涩,我們必須在自己的幫助類(lèi)里面重寫(xiě)這兩個(gè)方法忽孽,然后分別在這兩個(gè)方法中去 實(shí)現(xiàn)創(chuàng)建、升級(jí)數(shù)據(jù)庫(kù)的邏輯谢床。

  • 新建一個(gè)MySQLiteHelper類(lèi)并讓它 繼承SQLiteOpenHelper

public class MySQLiteHelper extends SQLiteOpenHelper {

    public MySQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    //實(shí)現(xiàn)創(chuàng)建的邏輯
    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    //實(shí)現(xiàn)升級(jí)數(shù)據(jù)庫(kù)的邏輯
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}
  • 其中兄一,當(dāng)數(shù)據(jù)庫(kù)創(chuàng)建的時(shí)候會(huì)調(diào)用onCreate()方法,在這里去執(zhí)行建表操作就可以了识腿。比如說(shuō)我們想新建一張news表出革,其中有title,content渡讼,publishdate骂束,commentcount這幾列,分別代表著新聞標(biāo)題成箫、新聞內(nèi)容栖雾、發(fā)布時(shí)間和評(píng)論數(shù),那么代碼就可以這樣寫(xiě):
public class MySQLiteHelper extends SQLiteOpenHelper {

    //建news表語(yǔ)句
    public static final String NEWS_TABLE = "create table news("
            + "id integer primary key autoincrement,"
            + "title text,"
            + "content text,"
            + "publishdata integer,"
            + "commentcount integer)";

    public MySQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    //實(shí)現(xiàn)創(chuàng)建的邏輯
    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建名為 “news” 的表
        db.execSQL(NEWS_TABLE);
    }

    //實(shí)現(xiàn)升級(jí)數(shù)據(jù)庫(kù)的邏輯
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

可以看到伟众,我們把建表語(yǔ)句定義成了一個(gè)常量析藕,然后在 onCreate()方法中去執(zhí)行了這條建表語(yǔ)句,news表也就創(chuàng)建成功了凳厢。這條建表語(yǔ)句雖然簡(jiǎn)單账胧,但是里面還是包含了一些小的細(xì)節(jié),我來(lái)解釋一下先紫。首先治泥,根據(jù)數(shù)據(jù)庫(kù)的范式要求,任何一張表都應(yīng)該是有主鍵的遮精,所以這里我們添加了一個(gè)自增長(zhǎng)的id列居夹,并把它設(shè)為主鍵败潦。然后title列和content列都是字符串類(lèi)型的,commentcount列是整型的准脂,這都很好理解劫扒,但是publishdate列該怎么設(shè)計(jì)呢?由于SQLite中并不支持存儲(chǔ)日期這種數(shù)據(jù)類(lèi)型狸膏,因此我們需要將日期先轉(zhuǎn)換成UTC時(shí)間(自1970年1月1號(hào)零點(diǎn))的毫秒數(shù)沟饥,然后再存儲(chǔ)到數(shù)據(jù)庫(kù)中,因此publishdate列也應(yīng)該是整型的湾戳。

  • 接著贤旷,我們只需要獲取到SQLiteDatabase的實(shí)例,數(shù)據(jù)庫(kù)表就會(huì)自動(dòng)創(chuàng)建了砾脑,如下所示:
SQLiteOpenHelper dbHelper = new MySQLiteHelper(this, "demo.db", null, 1);
// "demo.db" 就是數(shù)據(jù)庫(kù)名
        
 SQLiteDatabase db = dbHelper.getWritableDatabase();
  • 感覺(jué)很簡(jiǎn)單很方便是嗎幼驶?那你就太容易滿(mǎn)足了,下面我們就來(lái)學(xué)習(xí)一下LitePal的基本用法韧衣,看一看使用這個(gè)框架是如何實(shí)現(xiàn)同樣的功能的县遣。

1.2 使用LitePal建表

  • 雖說(shuō)LitePal宣稱(chēng)是近乎零配置,但也只是“近乎”而已汹族,它還是需要進(jìn)行一些簡(jiǎn)單配置才可以使用的,那么我們第一步就先快速學(xué)習(xí)一下LitePal的配置方法其兴。

1.2.1 快速配置

1. 引入Jar包或源碼

  • 首先我們需要將LitePal的jar包引入到項(xiàng)目當(dāng)中顶瞒,可以點(diǎn)擊這里查看LitePal的最新版本,選擇你需要的下載即可元旬。下載好了jar包之后榴徐,把它復(fù)制到項(xiàng)目的libs目錄中就算是引入成功了,如下圖所示:
    引入jar包
  • 如果不想用jar包的話匀归,也可以把LitePal的源碼下載下來(lái)坑资,然后作為一個(gè)library庫(kù)導(dǎo)入到Eclipse當(dāng)中,再讓我們的項(xiàng)目去引用這個(gè)library庫(kù)就可以了穆端。

2. 配置litepal.xml

  • 接著在項(xiàng)目的 assets目錄 (assets在main下)下面新建一個(gè)litepal.xml文件袱贮,并將以下代碼拷貝進(jìn)去:
<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  
  
    <version value="1" ></version>  
  
    <list>  
    </list>  
</litepal>  
  • 配置文件相當(dāng)簡(jiǎn)單,<dbname>用于設(shè)定數(shù)據(jù)庫(kù)的名字体啰,<version>用于設(shè)定數(shù)據(jù)庫(kù)的版本號(hào)攒巍,<list>用于設(shè)定所有的映射模型,我們稍后就會(huì)用到荒勇。

3. 配置LitePalApplication

  • 由于操作數(shù)據(jù)庫(kù)時(shí)需要用到 Context柒莉,而我們顯然不希望在每個(gè)接口中都去傳一遍這個(gè)參數(shù),那樣操作數(shù)據(jù)庫(kù)就顯得太繁瑣了沽翔。因此兢孝,LitePal使用了一個(gè)方法來(lái)簡(jiǎn)化掉Context這個(gè)參數(shù),只需要在 AndroidManifest.xml 中配置一下 LitePalApplication,所有的數(shù)據(jù)庫(kù)操作就都不用再傳Context了跨蟹,如下所示:
<manifest>  
    <application  
        android:name="org.litepal.LitePalApplication"  
        ...  
    >  
    ...  
    </application>  
</manifest>  
  • 當(dāng)然雳殊,有些程序可能會(huì)有自己的Application,并在這里配置過(guò)了喷市。比如說(shuō)有一個(gè)MyApplication相种,如下所示:
<manifest>  
    <application  
        android:name="com.example.MyApplication"  
        ...  
    >  
    ...  
    </application>  
</manifest>  
  • 沒(méi)有關(guān)系,這時(shí)只需要修改一下MyApplication的繼承結(jié)構(gòu)品姓,讓它不要直接繼承Application類(lèi)寝并,而是繼承LitePalApplication類(lèi),就可以使用一切都能正常工作了腹备,代碼如下所示:
public class MyApplication extends LitePalApplication {  
    ...  
}  
  • 但是衬潦,有些程序可能會(huì)遇到一些更加極端的情況,比如說(shuō)MyApplication需要繼承另外一個(gè)AnotherApplication植酥,并且這個(gè)AnotherApplication還是在jar包當(dāng)中的镀岛,不能修改它的代碼。這種情況應(yīng)該算是比較少見(jiàn)了友驮,但是如果你遇到了的話也不用急漂羊,仍然是有解釋方案的。你可以把LitePal的源碼下載下來(lái)卸留,然后把src目錄下的所有代碼直接拷貝到你項(xiàng)目的src目錄下面走越,接著打開(kāi)LitePalApplication類(lèi),將它的繼承結(jié)構(gòu)改成繼承自AnotherApplication耻瑟,再讓MyApplication繼承自LitePalApplication旨指,這樣所有的Application就都可以在一起正常工作了。
  • 僅僅三步喳整,我們就將所有的配置工作全部完成了谆构,并且這是一件一本萬(wàn)利的事情,自此以后框都,你就可以開(kāi)心地體驗(yàn)LitePal提供的各種便利了搬素,就讓我們從建表開(kāi)始吧。

1.2.2 LitePal建表

  • 前面在介紹的時(shí)候已經(jīng)說(shuō)了魏保,LitePal采取的是對(duì)象關(guān)系映射(ORM)的模式蔗蹋,那么什么是對(duì)象關(guān)系映射呢?簡(jiǎn)單點(diǎn)說(shuō)囱淋,我們使用的編程語(yǔ)言是面向?qū)ο笳Z(yǔ)言猪杭,而我們使用的數(shù)據(jù)庫(kù)則是關(guān)系型數(shù)據(jù)庫(kù),那么將面向?qū)ο蟮恼Z(yǔ)言和面向關(guān)系的數(shù)據(jù)庫(kù)之間建立一種映射關(guān)系妥衣,這就是對(duì)象關(guān)系映射了皂吮。

但是我們?yōu)槭裁匆褂脤?duì)象關(guān)系映射模式呢戒傻?這主要是因?yàn)榇蠖鄶?shù)的程序員都很擅長(zhǎng)面向?qū)ο缶幊蹋渲兄挥猩俨糠值娜瞬疟容^精通關(guān)系型數(shù)據(jù)庫(kù)蜂筹。而且數(shù)據(jù)庫(kù)的SQL語(yǔ)言晦澀難懂需纳,就算你很精通它,恐怕也不喜歡經(jīng)常在代碼中去寫(xiě)它吧艺挪?而對(duì)象關(guān)系映射模式則很好地解決了這個(gè)問(wèn)題不翩,它允許我們使用面向?qū)ο蟮姆绞絹?lái)操作數(shù)據(jù)庫(kù),從而可以從晦澀難懂的SQL語(yǔ)言中解脫出來(lái)麻裳。

  • 那么接下來(lái)我們就看一看LitePal中是如何建表的吧口蝠。根據(jù)對(duì)象關(guān)系映射模式的理念,每一張表都應(yīng)該對(duì)應(yīng)一個(gè) 模型(Model)津坑,也就是說(shuō)妙蔗,如果我們想要建一張news表,就應(yīng)該有一個(gè)對(duì)應(yīng)的News模型類(lèi)疆瑰。新建一個(gè) News類(lèi)眉反,如下所示:
package com.example.databasetest.model;  
public class News {  
}  
  • 然后,表中的每一列其實(shí)就是對(duì)應(yīng)了模型類(lèi)中的一個(gè)字段穆役,比如news表中有id寸五、title、content耿币、publishdate梳杏、commentcount這幾個(gè)列,那么在News類(lèi)中就也應(yīng)該有這幾個(gè)字段掰读,代碼如下所示:
public class News {  
      
    private int id;  
      
    private String title;  
      
    private String content;  
      
    private Date publishDate;  
      
    private int commentCount;  
      
    // 自動(dòng)生成get、set方法  
    ...  
}  

其中id這個(gè)字段可寫(xiě)可不寫(xiě)叭莫,因?yàn)榧词共粚?xiě)這個(gè)字段蹈集,LitePal也會(huì)在表中自動(dòng)生成一個(gè)id列,畢竟每張表都一定要有主鍵的嘛雇初。

  • 這里要特別說(shuō)明一下拢肆,LitePal的映射規(guī)則是非常輕量級(jí)的,不像一些其它的數(shù)據(jù)庫(kù)框架靖诗,需要為每個(gè)模型類(lèi)單獨(dú)配置一個(gè)映射關(guān)系的XML郭怪,LitePal的所有映射都是自動(dòng)完成的。根據(jù)LitePal的數(shù)據(jù)類(lèi)型支持刊橘,可以進(jìn)行對(duì)象關(guān)系映射的數(shù)據(jù)類(lèi)型一共有8種鄙才,int、short促绵、long攒庵、float嘴纺、double、boolean浓冒、String和Date栽渴。只要是聲明成這8種數(shù)據(jù)類(lèi)型的字段都會(huì)被自動(dòng)映射到數(shù)據(jù)庫(kù)表中,并不需要進(jìn)行任何額外的配置稳懒。

  • 現(xiàn)在模型類(lèi)已經(jīng)建好了闲擦,我們還差最后一步,就是將它配置到映射列表當(dāng)中场梆。編輯assets目錄下的litepal.xml文件墅冷,在<list>標(biāo)簽中加入News模型類(lèi)的聲明:

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  
  
    <version value="1" ></version>  
  
    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping>  
    </list>  
</litepal>  

注意這里一定要填入News類(lèi)的完整類(lèi)名。

  • OK辙谜,這樣所有的工作就都已經(jīng)完成了俺榆,現(xiàn)在只要你對(duì)數(shù)據(jù)庫(kù)有任何的操作,news表就會(huì)被自動(dòng)創(chuàng)建出來(lái)装哆。比如說(shuō)LitePal提供了一個(gè)便捷的方法來(lái)獲取到SQLiteDatabase的實(shí)例罐脊,如下所示:
 //LitePal 獲取實(shí)例
 SQLiteDatabase db = Connector.getDatabase();
  • 調(diào)用一下上述代碼,news表就應(yīng)該已經(jīng)創(chuàng)建成功了蜕琴。我們使用SQLite命令來(lái)查看一下萍桌,打開(kāi)demo.db數(shù)據(jù)庫(kù),輸入.table命令凌简,結(jié)果如下圖所示:


    20140907222357271.png
  • 可以看到上炎,news表已經(jīng)存在了。另外兩張android_metadata和table_schema表是自動(dòng)生成的雏搂,我們不用理藕施。接下來(lái)我們還可以再查詢(xún)一下news表的建表語(yǔ)句,如下圖所示:


    20140907222630369.png
  • 這就是LitePal根據(jù)News類(lèi)中的字段自動(dòng)幫我們生成的建表語(yǔ)句凸郑,由此也說(shuō)明裳食,建表操作已經(jīng)成功完成了。

2芙沥、升級(jí)表

  • 創(chuàng)建表只是數(shù)據(jù)庫(kù)操作中最基本的一步而已诲祸,我們?cè)谝婚_(kāi)始創(chuàng)建的表結(jié)構(gòu),隨著需求的變更而昨,到了后期是極有可能需要修改的救氯。因此,升級(jí)表的操作對(duì)于任何一個(gè)項(xiàng)目也是至關(guān)重要的歌憨,那么今天我們就一起來(lái)學(xué)習(xí)一下着憨,在Android傳統(tǒng)開(kāi)發(fā)當(dāng)中升級(jí)表的方式,以及使用LitePal來(lái)進(jìn)行升級(jí)表操作的用法务嫡。

2.1 傳統(tǒng)的升級(jí)表方式

  • 上一節(jié)文章中我們借助MySQLiteHelper已經(jīng)創(chuàng)建好了news這張表享扔,這也是demo.db這個(gè)數(shù)據(jù)庫(kù)的第一個(gè)版本底桂。然而,現(xiàn)在需求發(fā)生了變更惧眠,我們的軟件除了能看新聞之外籽懦,還應(yīng)該允許用戶(hù)評(píng)論,所以這時(shí)就需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行升級(jí)氛魁,添加一個(gè)comment表暮顺。

  • 該怎么做呢?添加一個(gè)comment表的建表語(yǔ)句秀存,然后在onCreate()方法中去執(zhí)行它捶码?沒(méi)錯(cuò),這樣的話或链,兩張表就會(huì)同時(shí)創(chuàng)建了惫恼,代碼如下所示:

public class MySQLiteHelper extends SQLiteOpenHelper {

    //建news表語(yǔ)句
    public static final String NEWS_TABLE = "create table news("
            + "id integer primary key autoincrement,"
            + "title text,"
            + "content text,"
            + "publishdata integer,"
            + "commentcount integer)";

    //建comment表語(yǔ)句
    public static final String COMMENT_TABLE = "create table comment("
            + "id integer primary key autoincrement,"
            + "content text)";

    public MySQLiteHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    //實(shí)現(xiàn)創(chuàng)建的邏輯
    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建名為 “news” 的表
        db.execSQL(NEWS_TABLE);

        //創(chuàng)建名為 “comment” 的表
        db.execSQL(COMMENT_TABLE);
    }

    //實(shí)現(xiàn)升級(jí)數(shù)據(jù)庫(kù)的邏輯
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}
  • 這對(duì)于第一次安裝我們軟件的用戶(hù)來(lái)說(shuō)是完全可以正常工作的,但是如果有的用戶(hù)已經(jīng)安裝過(guò)上一版的軟件澳盐,那么很遺憾祈纯,comment表是創(chuàng)建不出來(lái)的,因?yàn)橹皵?shù)據(jù)庫(kù)就已經(jīng)創(chuàng)建過(guò)了叼耙,onCreate()方法是不會(huì)重新執(zhí)行的腕窥。

  • 對(duì)于這種情況我們就要用升級(jí)的方式來(lái)解決了,看到MySQLiteHelper構(gòu)造方法中的第四個(gè)參數(shù)了嗎筛婉,這個(gè)就是數(shù)據(jù)庫(kù)版本號(hào)的標(biāo)識(shí)簇爆,每當(dāng)版本號(hào)增加的時(shí)候就會(huì)調(diào)用onUpgrade()方法,我們只需要在這里處理升級(jí)表的操作就行了爽撒。比較簡(jiǎn)單粗暴的方式是將數(shù)據(jù)庫(kù)中現(xiàn)有的所有表都刪除掉入蛆,然后重新創(chuàng)建,代碼如下所示:

public class MySQLiteHelper extends SQLiteOpenHelper {

    .....

    //實(shí)現(xiàn)創(chuàng)建的邏輯
    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建名為 “news” 的表
        db.execSQL(NEWS_TABLE);

        //創(chuàng)建名為 “comment” 的表
        db.execSQL(COMMENT_TABLE);
    }

    //實(shí)現(xiàn)升級(jí)數(shù)據(jù)庫(kù)的邏輯
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //刪除 “news” 表
        db.execSQL("drop table if exists news");
        
        //調(diào)用onCreate重新建表
        onCreate(db);
    }
}

可以看到硕勿,當(dāng)數(shù)據(jù)庫(kù)升級(jí)的時(shí)候哨毁,我們先把news表刪除掉,然后重新執(zhí)行了一次onCreate()方法首尼,這樣就保證數(shù)據(jù)庫(kù)中的表都是最新的了挑庶。

  • 但是言秸,如果news表中本來(lái)已經(jīng)有數(shù)據(jù)了软能,使用這種方式升級(jí)的話,就會(huì)導(dǎo)致表中的數(shù)據(jù)全部丟失举畸,所以這并不是一種值得推薦的升級(jí)方法查排。那么更好的升級(jí)方法是什么樣的呢?這就稍微有些復(fù)雜了抄沮,需要在onUpgrade()方法中根據(jù)版本號(hào)加入具體的升級(jí)邏輯跋核,我們來(lái)試試來(lái)吧岖瑰。比如之前的數(shù)據(jù)庫(kù)版本號(hào)是1,那么在onUpgrade()方法中就可以這樣寫(xiě):
public class MySQLiteHelper extends SQLiteOpenHelper {

    ......

    //實(shí)現(xiàn)創(chuàng)建的邏輯
    @Override
    public void onCreate(SQLiteDatabase db) {
        //創(chuàng)建名為 “news” 的表
        db.execSQL(NEWS_TABLE);

        //創(chuàng)建名為 “comment” 的表
        db.execSQL(COMMENT_TABLE);
    }

    //實(shí)現(xiàn)升級(jí)數(shù)據(jù)庫(kù)的邏輯
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
            case 1:
                db.execSQL(COMMENT_TABLE);
            default:
        }
    }
}
  • 可以看到砂代,這里在 onUpgrade() 方法中加入了一個(gè)switch判斷蹋订,如果oldVersion等于1,就再創(chuàng)建一個(gè)comment表】桃粒現(xiàn)在只需要調(diào)用如下代碼露戒,表就可以得到創(chuàng)建或升級(jí)了:
SQLiteOpenHelper dbHelper = new MySQLiteHelper(this, "demo.db", null, 2);
        
 SQLiteDatabase db = dbHelper.getWritableDatabase();

這里我們將版本號(hào)加1,如果用戶(hù)是從舊版本升級(jí)過(guò)來(lái)的捶箱,就會(huì)新增一個(gè)comment表智什,而如果用戶(hù)是直接安裝的新版本,就會(huì)在onCreate()方法中把兩個(gè)表一起創(chuàng)建了丁屎。

  • OK荠锭,現(xiàn)在軟件的第二版本也發(fā)布出去了,可是就在發(fā)布不久之后晨川,突然發(fā)現(xiàn) comment表中少了一個(gè)字段证九,我們并沒(méi)有記錄評(píng)論發(fā)布的時(shí)間。沒(méi)辦法础爬,只好在第三版中修復(fù)這個(gè)問(wèn)題了甫贯,那我們?cè)撛趺礃尤ヌ砑舆@個(gè)字段呢?主要需要修改comment表的建表語(yǔ)句看蚜,以及onUpgrade()方法中的邏輯叫搁,代碼如下所示:
public class MySQLiteHelper extends SQLiteOpenHelper {

    ......

    //建comment表語(yǔ)句
    public static final String COMMENT_TABLE = "create table comment("
            + "id integer primary key autoincrement,"
            + "content text,"
            + "publishdate integer)";   //增加字段

    ......

    //實(shí)現(xiàn)升級(jí)數(shù)據(jù)庫(kù)的邏輯
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch (oldVersion) {
            case 1:
                db.execSQL(COMMENT_TABLE);
                //case中別用break
            case 2:
                //增加字段
                db.execSQL("alter table comment add column publishdate integer");
                //case中別用break
            default:
            break供炎;//這這里break渴逻,防止從1~3的情況()
        }
    }
}
  • 可以看到,在建表語(yǔ)句當(dāng)中我們新增了publishdate這一列音诫,這樣當(dāng)執(zhí)行onCreate()方法去創(chuàng)建表的時(shí)候惨奕,comment表中就會(huì)有這一列了。那么如果是從舊版本升級(jí)過(guò)來(lái)的呢竭钝?也沒(méi)有問(wèn)題蒙挑,我們?cè)趏nUpgrade()方法中已經(jīng)把升級(jí)邏輯都處理好了,當(dāng)oldVersion等于2的時(shí)候筛璧,會(huì)執(zhí)行alter語(yǔ)句來(lái)添加publishdate這一列∶。現(xiàn)在調(diào)用以下代碼來(lái)創(chuàng)建或升級(jí)數(shù)據(jù)庫(kù):
SQLiteOpenHelper dbHelper = new MySQLiteHelper(this, "demo.db", null, 3);

  SQLiteDatabase db = dbHelper.getWritableDatabase();

將數(shù)據(jù)庫(kù)版本號(hào)設(shè)置成3,這樣就可以保證數(shù)據(jù)庫(kù)中的表又是最新的了庇茫。

  • 現(xiàn)在我們已經(jīng)學(xué)習(xí)了新增表和新增列這兩種升級(jí)方式港粱,那么如果是某張表中的某一列已經(jīng)沒(méi)有用了,我想把這一列刪除掉該怎么寫(xiě)呢旦签?很遺憾查坪,SQLite并不支持刪除列的功能寸宏,對(duì)于這情況,多數(shù)軟件采取的作法是無(wú)視它偿曙,反正以后也用不到它了氮凝,留著也占不了什么空間,所以針對(duì)于這種需求望忆,確實(shí)沒(méi)什么簡(jiǎn)單的解決辦法覆醇。

  • 這大概就是傳統(tǒng)開(kāi)發(fā)當(dāng)中升級(jí)數(shù)據(jù)庫(kù)表的方式了,雖說(shuō)能寫(xiě)出這樣的代碼表示你已經(jīng)對(duì)數(shù)據(jù)庫(kù)的升級(jí)操作理解的比較清楚了炭臭,但隨著版本越來(lái)越多永脓,onUpgrade()方法中的邏輯也會(huì)變得愈發(fā)復(fù)雜,稍微一不留神鞋仍,也許就會(huì)產(chǎn)生錯(cuò)誤常摧。因此,如果能讓代碼自動(dòng)控制升級(jí)邏輯威创,而不是由人工來(lái)管理落午,那就是再好不過(guò)了,那么下面我們就來(lái)學(xué)習(xí)一下怎樣使用LitePal來(lái)進(jìn)行升級(jí)表的操作肚豺。

2.2 使用LitePal升級(jí)表

  • 通過(guò)上文的學(xué)習(xí)溃斋,我們已經(jīng)知道LitePal是一款ORM模式的框架了,已經(jīng)熟悉創(chuàng)建表流程的你吸申,相信對(duì)于升級(jí)表也一定會(huì)輕車(chē)熟路的梗劫。那么為了模仿傳統(tǒng)升級(jí)表方式中的需求,現(xiàn)在我們也需要?jiǎng)?chuàng)建一張comment表截碴。第一步該怎么辦呢梳侨?相信你也許早就已經(jīng)猜到了,那當(dāng)然是先創(chuàng)建一個(gè)Comment類(lèi)了日丹,如下所示:
package com.example.databasetest.model;  
public class Comment {  
      
    private int id;  
      
    private String content;  
      
    // 自動(dòng)生成get走哺、set方法   
    ...  
}  

OK,Comment類(lèi)中有id和content這兩個(gè)字段哲虾,也就意味著comment表中會(huì)有id和content這兩列丙躏。

  • 接著修改litepal.xml中的配置,在映射列表中新增Comment類(lèi)束凑,并將版本號(hào)加1晒旅,如下所示:
<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  
  
    <version value="2" ></version>  
  
    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping>  
        <mapping class="com.example.databasetest.model.Comment"></mapping>  
    </list>  
</litepal>  
  • 沒(méi)錯(cuò),就是這么簡(jiǎn)單湘今,僅僅兩步敢朱,升級(jí)的操作就已經(jīng)完成了剪菱,現(xiàn)在我們只需要操作一下數(shù)據(jù)庫(kù)摩瞎,comment表就會(huì)自動(dòng)生成了拴签,如下所示:
//LitePal 獲取實(shí)例
 SQLiteDatabase db = Connector.getDatabase();
  • 那么我們還是通過(guò).table命令來(lái)查看一下結(jié)果,如下圖所示:


    20140914155958796.png
  • OK旗们,comment表已經(jīng)出來(lái)了蚓哩,那么再通過(guò)pragma命令來(lái)查看一下它的表結(jié)構(gòu)吧:


    20140914160140852.png

沒(méi)有問(wèn)題,comment表中目前有id和content這兩列上渴,和Comment模型類(lèi)中的字段是保持一致的岸梨。

  • 那么現(xiàn)在又來(lái)了新的需求,需要在 comment表中添加一個(gè)publishdate列稠氮,該怎么辦呢曹阔?不用懷疑,跟著你的直覺(jué)走隔披,相信你已經(jīng)猜到應(yīng)該在Comment類(lèi)中添加這樣一個(gè)字段了吧赃份,如下所示:
public class Comment {  
      
    private int id;  
      
    private String content;  
      
    private Date publishDate;  
      
    // 自動(dòng)生成get、set方法   
    ...  
}  
  • 然后呢奢米?剩下的操作已經(jīng)非常簡(jiǎn)單了抓韩,只需要在litepal.xml中對(duì)版本號(hào)加1就行了,如下所示:
<litepal>  
    <dbname value="demo" ></dbname>  
  
    <version value="3" ></version>  
    ...  
</litepal>  
  • 這樣當(dāng)我們下一次操作數(shù)據(jù)庫(kù)的時(shí)候鬓长,publishdate列就應(yīng)該會(huì)自動(dòng)添加到comment表中谒拴。調(diào)用Connector.getDatabase()方法,然后重新查詢(xún)comment表結(jié)構(gòu)涉波,如下所示:


    20140914161913495.png

可以看到英上,publishdate這一列確實(shí)已經(jīng)成功添加到comment表中了。

2.3 兩種方式總結(jié)

  • 通過(guò)這兩種升級(jí)方式的對(duì)比啤覆,相信你已經(jīng)充分體會(huì)到了使用LitePal進(jìn)行升級(jí)表操作所帶來(lái)的便利了吧善延。我們不需要去編寫(xiě)任何與升級(jí)相關(guān)的邏輯,也不需要關(guān)心程序是從哪個(gè)版本升級(jí)過(guò)來(lái)的城侧,唯一要做的就是確定好最新的Model結(jié)構(gòu)是什么樣的易遣,然后將litepal.xml中的版本號(hào)加1,所有的升級(jí)邏輯就都會(huì)自動(dòng)完成了嫌佑。LitePal確實(shí)將數(shù)據(jù)庫(kù)表的升級(jí)操作變得極度簡(jiǎn)單豆茫,使很多程序員可以從維護(hù)數(shù)據(jù)庫(kù)表升級(jí)的困擾中解脫出來(lái)。

  • 然而屋摇,LitePal卻明顯做到了更好揩魂。前面我們提到過(guò)關(guān)于刪除列的問(wèn)題,最終的結(jié)論是無(wú)法解決炮温,因?yàn)镾QLite是不支持刪除列的命令的火脉。但是如果使用LitePal,這一問(wèn)題就可以簡(jiǎn)單地解決掉,比如說(shuō)publishdate這一列我們又不想要了倦挂,那么只需要在Comment類(lèi)中把它刪除掉畸颅,然后將版本號(hào)加1,下次操作數(shù)據(jù)庫(kù)的時(shí)候這個(gè)列就會(huì)不見(jiàn)了方援。

  • 那么有的朋友可能會(huì)問(wèn)了没炒,不是說(shuō)SQLite不支持刪除列的命令嗎?那LitePal又是怎樣做到的呢犯戏?其實(shí)LitePal并沒(méi)有刪除任何一列送火,它只是先將comment表重命名成一個(gè)臨時(shí)表,然后根據(jù)最新的Comment類(lèi)的結(jié)構(gòu)生成一個(gè)新的comment表先匪,再把臨時(shí)表中除了publishdate之外的數(shù)據(jù)復(fù)制到新的表中种吸,最后把臨時(shí)表刪掉。因此呀非,看上去的效果好像是做到了刪除列的功能骨稿。

  • 這也是使用框架的好處,如果沒(méi)有框架的幫助姜钳,我們顯然不會(huì)為了刪除一個(gè)列而大廢周章地去寫(xiě)這么多的代碼坦冠,而使用框架的話,具體的實(shí)現(xiàn)邏輯我們已經(jīng)不用再關(guān)心哥桥,只需要控制好模型類(lèi)的數(shù)據(jù)結(jié)構(gòu)就可以了辙浑。

  • 另外,如果你想刪除某一張表的話拟糕,操作也很簡(jiǎn)單判呕,在litepal.xml中的映射列表中將相應(yīng)的類(lèi)刪除,表自然也就不存在了送滞。其它的一些升級(jí)操作也都是類(lèi)似的侠草,相信你已經(jīng)能舉一反三,這里就不再贅述了犁嗅。

3边涕、建立表關(guān)聯(lián)

3.1 關(guān)聯(lián)關(guān)系的基礎(chǔ)知識(shí)

  • 喜歡把所有的代碼都寫(xiě)在一個(gè)類(lèi)里的程序員肯定是個(gè)新手。沒(méi)錯(cuò)褂微,任何一個(gè)像樣的程序都不可能僅僅只有一個(gè)類(lèi)的功蜓,同樣地,任何一個(gè)像樣的數(shù)據(jù)庫(kù)也不可能僅僅只有一張表宠蚂。我們都知道式撼,在面向?qū)ο蟮木幊陶Z(yǔ)言中,多個(gè)類(lèi)之間可以相互關(guān)聯(lián)引用求厕,共同完成某項(xiàng)功能著隆。那么在數(shù)據(jù)庫(kù)當(dāng)中扰楼,多個(gè)表之間可以相互關(guān)聯(lián)嗎?當(dāng)然可以美浦!只不過(guò)表與表之間的關(guān)聯(lián)關(guān)系要比對(duì)象之間的關(guān)聯(lián)關(guān)系復(fù)雜一些弦赖,也更加難懂,但是作為數(shù)據(jù)庫(kù)的基本功抵代,還是應(yīng)該了解清楚的,那么我們就先來(lái)學(xué)習(xí)一下數(shù)據(jù)庫(kù)表關(guān)聯(lián)的基礎(chǔ)知識(shí)忘嫉。

  • 表與表之間的關(guān)聯(lián)關(guān)系一共有三種類(lèi)型荤牍,一對(duì)一、多對(duì)一庆冕、和多對(duì)多康吵,下面我們分別對(duì)這三種類(lèi)型展開(kāi)進(jìn)行討論。

一對(duì)一

  • 表示兩個(gè)表中的數(shù)據(jù)必須是一一對(duì)應(yīng)的關(guān)系访递。這種場(chǎng)景其實(shí)并不是很常見(jiàn)晦嵌,我們還是通過(guò)例子來(lái)直觀地體會(huì)一下,例子仍然是在之前文章的基礎(chǔ)上展開(kāi)的拷姿。

  • 現(xiàn)在我們已經(jīng)創(chuàng)建好了news這張表惭载,里面主要記錄了新聞的標(biāo)題和內(nèi)容,那么除了標(biāo)題和內(nèi)容之外响巢,有些新聞還可能帶有一些導(dǎo)語(yǔ)和摘要描滔,我們把這兩個(gè)字段放在一張introduction表中,作為新聞的簡(jiǎn)介踪古。那么很顯然含长,news表和introduction表就是一對(duì)一的關(guān)系了,因?yàn)橐粭l新聞只能對(duì)應(yīng)一個(gè)簡(jiǎn)介伏穆,一個(gè)簡(jiǎn)介也只能屬于一條新聞拘泞。它們之間的對(duì)應(yīng)關(guān)系大概如下圖描述的一樣:


    一對(duì)一

可以看到,News1對(duì)應(yīng)了Introduction2枕扫,News2對(duì)應(yīng)了Introduction3陪腌,News3對(duì)應(yīng)了Introduction1,但不管怎么樣烟瞧,它們都是一對(duì)一的關(guān)系偷厦。

  • 那么這種一對(duì)一的關(guān)系,在編程語(yǔ)言中該怎么體現(xiàn)出來(lái)呢燕刻?相信熟悉面向?qū)ο笤O(shè)計(jì)的你只泼,一定很輕松就能想出來(lái)吧,只需要在News類(lèi)中持有一個(gè)Introduction類(lèi)的引用卵洗,然后在Introduction類(lèi)中也持有一個(gè)News類(lèi)的引用请唱,這樣它們之間自然就是一對(duì)一的關(guān)系了弥咪。

  • 沒(méi)錯(cuò),對(duì)象之間的一對(duì)一關(guān)系非常簡(jiǎn)單易懂十绑,那么難點(diǎn)就在于聚至,如何在數(shù)據(jù)庫(kù)表中建立這樣的一對(duì)一關(guān)系了。由于數(shù)據(jù)庫(kù)并不像面向?qū)ο蟮恼Z(yǔ)言一樣支持相互引用本橙,如果想讓兩張表之間建立一對(duì)一的關(guān)系扳躬,一般就只能通過(guò)外鍵的方式來(lái)實(shí)現(xiàn)了。因此甚亭,一對(duì)一關(guān)系的表結(jié)構(gòu)就可以這樣設(shè)計(jì):


    一對(duì)一表結(jié)構(gòu)
  • 請(qǐng)注意贷币,introduction表中有一個(gè)news_id列,這是一個(gè)外鍵列亏狰,里面應(yīng)該存放一個(gè)具體的新聞id役纹,這樣一條introduction就能對(duì)應(yīng)一條news,也就實(shí)現(xiàn)一對(duì)一的關(guān)系了暇唾,如下圖所示:


  • 由此我們就能夠看出促脉,id為1的introduction對(duì)應(yīng)著id為2的news,id為2的introduction對(duì)應(yīng)著id為3的news策州,id為3的introduction對(duì)應(yīng)著id為1的news瘸味。需要注意的是,一對(duì)一的關(guān)系并沒(méi)有強(qiáng)制要求外鍵必須加在哪一張表上够挂,你可以在introduction表中加一個(gè)news_id作為外鍵硫戈,也可以在news表中加一個(gè)introduction_id作為外鍵,不管使用哪一種下硕,都可以表示出它們是一對(duì)一的關(guān)聯(lián)關(guān)系丁逝。

多對(duì)一

  • 表示一張表中的數(shù)據(jù)可以對(duì)應(yīng)另一張表中的多條數(shù)據(jù)。這種場(chǎng)景比起一對(duì)一關(guān)系就要常見(jiàn)太多了梭姓,在我們平時(shí)的開(kāi)發(fā)工作中多對(duì)一關(guān)系真的是比比皆是霜幼。比如說(shuō)現(xiàn)在我們的數(shù)據(jù)庫(kù)中有一個(gè)news表,還有一個(gè)comment表誉尖,它們兩個(gè)之間就是典型的多對(duì)一關(guān)系罪既,一條新聞可以有很多條評(píng)論,但是一條評(píng)論只能是屬于一條新聞的铡恕。它們的關(guān)系如下圖所示:


    多對(duì)一
  • 而這種多對(duì)一的關(guān)系在編程語(yǔ)言中是非常容易體現(xiàn)出來(lái)的琢感,比如Java中就有專(zhuān)門(mén)集合類(lèi),如List探熔、Set等驹针,使用它們的話就能輕松簡(jiǎn)單地在對(duì)象之間建立多對(duì)一的關(guān)系,我們稍后就會(huì)看到诀艰。那么柬甥,這里的難點(diǎn)仍然是在數(shù)據(jù)庫(kù)表中如何建立這樣的多對(duì)一關(guān)系∫現(xiàn)在說(shuō)難點(diǎn)其實(shí)已經(jīng)不難了,因?yàn)榍懊嫖覀円呀?jīng)學(xué)會(huì)了一對(duì)一關(guān)系的建立方法苛蒲,而多對(duì)一也是類(lèi)似的卤橄。沒(méi)錯(cuò),數(shù)據(jù)庫(kù)表中多對(duì)一的關(guān)系仍然是通過(guò)外鍵來(lái)建立的臂外,只不過(guò)一對(duì)一的時(shí)候外鍵加在哪一張表上都可以窟扑,但多對(duì)一的時(shí)候關(guān)鍵必須要加在多方的表中。因此漏健,多對(duì)一關(guān)系的表結(jié)構(gòu)就可以這樣設(shè)計(jì):

    表結(jié)構(gòu)

  • 在comment表中有一個(gè)news_id列嚎货,這是一個(gè)外鍵列,里面應(yīng)該存放一個(gè)具體的新聞id漾肮,并且允許多條comment都存放同一個(gè)新聞id厂抖,這樣一條評(píng)論就只能對(duì)應(yīng)一條新聞茎毁,但一條新聞卻可以有多條評(píng)論克懊,也就實(shí)現(xiàn)多對(duì)一的關(guān)系了,如下圖所示:


  • 由此我們就可以看出七蜘,id為1谭溉、2、3的三條評(píng)論是屬于第一條新聞的橡卤,而id為4扮念、5的兩條評(píng)論是屬于第二條新聞的。

多對(duì)多

  • 表示兩張關(guān)聯(lián)表中的數(shù)據(jù)都可以對(duì)應(yīng)另一張表中的多條數(shù)據(jù)碧库。這種場(chǎng)景也不算是很常見(jiàn)柜与,但比一對(duì)一關(guān)系要稍微更加常用一些。舉個(gè)例子嵌灰,我們都知道新聞網(wǎng)站是會(huì)將新聞進(jìn)行種類(lèi)劃分的弄匕,這樣用戶(hù)就可以選擇自己喜歡的那一類(lèi)新聞進(jìn)行瀏覽,比如說(shuō)網(wǎng)易新聞中就會(huì)有頭條沽瞭、科技迁匠、娛樂(lè)、手機(jī)等等種類(lèi)驹溃。每個(gè)種類(lèi)下面當(dāng)然都會(huì)有許多條新聞城丧,而一條新聞也可能是屬于多個(gè)種類(lèi)的,比如iPhone6發(fā)布的新聞既可以屬于手機(jī)種類(lèi)豌鹤,也可以屬于科技種類(lèi)亡哄,甚至還可以上頭條。因此布疙,新聞和種類(lèi)之間就是一種多對(duì)多的關(guān)系磺平,如下圖所示:


    多對(duì)多
  • 可以看到魂仍,News1是屬于Category1的,而News2和News3都是既屬于Category1也屬于Category2拣挪,如此復(fù)雜的關(guān)聯(lián)關(guān)系該如何表示呢擦酌?在面向?qū)ο蟮木幊陶Z(yǔ)言中一切都是那么的簡(jiǎn)單,只需要在News類(lèi)中使用集合類(lèi)聲明擁有多個(gè)Category菠劝,然后在Category類(lèi)中也使用集合類(lèi)聲明擁有多個(gè)News就可以了赊舶,我們稍后就會(huì)看到。而難點(diǎn)仍然是留在了數(shù)據(jù)庫(kù)上赶诊,兩張表之間如何建立多對(duì)多的關(guān)聯(lián)關(guān)系呢笼平,還是用外鍵嗎?肯定不行了舔痪,多對(duì)多的情況只能是借助中間表來(lái)完成了寓调。也就是說(shuō),我們需要多建立一張表锄码,這張表沒(méi)什么其它作用夺英,就是為了存放news表和category表之間的關(guān)聯(lián)關(guān)系的,如下圖所示:


    表結(jié)構(gòu)
  • 注意這里我們建立一張名為category_news的中間表滋捶,中間表的命名并沒(méi)有什么強(qiáng)制性的約束痛悯,但一個(gè)良好的命名規(guī)范可以讓你一眼就明白這張表是用來(lái)做什么的。中間表里面只有兩列重窟,而且也只需要有兩列载萌,分別是news表的外鍵和category表的外鍵,在這里存放新聞和種類(lèi)相應(yīng)的id巡扇,就可以讓它們之間建立關(guān)聯(lián)關(guān)系了扭仁,如下圖所示:


  • 由此我們就可以看出,第一條新聞是屬于第一個(gè)種類(lèi)的厅翔,而第二和第三條新聞乖坠,則既屬于第一個(gè)種類(lèi),也屬于第二個(gè)種類(lèi)知给。反過(guò)來(lái)也可以這樣看瓤帚,第一個(gè)種類(lèi)下面有第一、第二涩赢、第三這三條新聞戈次,而第二個(gè)種類(lèi)下面只有第二、第三這兩條新聞筒扒。不管怎么看怯邪,多對(duì)多的關(guān)系都是成立的。

  • 好了花墩,三種關(guān)聯(lián)關(guān)系都講完了悬秉,那我們來(lái)簡(jiǎn)單總結(jié)一下吧澄步。雖說(shuō)上面介紹了花了很大的篇幅講解數(shù)據(jù)庫(kù)的表關(guān)聯(lián)知識(shí),但其實(shí)最后的結(jié)論是非常簡(jiǎn)單的和泌,大家可以當(dāng)成口訣一樣背下來(lái)村缸。即一對(duì)一關(guān)聯(lián)的實(shí)現(xiàn)方式是用外鍵,多對(duì)一關(guān)聯(lián)的實(shí)現(xiàn)方式也是用外鍵武氓,多對(duì)多關(guān)聯(lián)的實(shí)現(xiàn)方式是用中間表梯皿。記下了這個(gè)口訣,在很多數(shù)據(jù)庫(kù)設(shè)計(jì)的時(shí)候县恕,你都可以發(fā)揮得更加游刃有余东羹。

3.2 使用LitePal建立表關(guān)聯(lián)

  • 雖說(shuō)口訣就是這個(gè)樣子,但牽扯到表關(guān)聯(lián)的時(shí)候畢竟增加了建表的難度忠烛,建表語(yǔ)句會(huì)更加復(fù)雜属提,你也需要格外地小心以防止出現(xiàn)什么錯(cuò)誤。因此美尸,使用LitePal來(lái)自動(dòng)建立表關(guān)聯(lián)又是一個(gè)非常不錯(cuò)的選擇冤议,我們不需要關(guān)心什么外鍵、中間表等實(shí)現(xiàn)的細(xì)節(jié)火惊,只需要在對(duì)象中聲明好它們相互之間的引用關(guān)系求类,LitePal就會(huì)自動(dòng)在數(shù)據(jù)庫(kù)表之間建立好相應(yīng)的關(guān)聯(lián)關(guān)系了奔垦,下面我們就來(lái)嘗試一下吧屹耐。

  • 首先確定一下一共涉及到了哪些實(shí)體類(lèi),News和Comment椿猎,這兩個(gè)類(lèi)我們?cè)谇皟善恼轮芯鸵呀?jīng)建好了惶岭,然后還需要有Introduction和Category這兩個(gè)類(lèi),新建Introduction類(lèi)犯眠,代碼如下所示:

public class Introduction {  
      
    private int id;  
      
    private String guide;  
      
    private String digest;  
      
    // 自動(dòng)生成get按灶、set方法
    ......  
}  
  • 接著新建Category類(lèi),代碼如下所示:
public class Category {  
      
    private int id;  
      
    private String name;  
      
    // 自動(dòng)生成get筐咧、set方法 
    ...... 
}  
  • 現(xiàn)在四個(gè)類(lèi)都已經(jīng)建好了鸯旁,但目前它們都還是各自獨(dú)立的,互相之間沒(méi)有任何聯(lián)系量蕊,那么我們現(xiàn)在就開(kāi)始用極為簡(jiǎn)單易懂的方式來(lái)給它們建立關(guān)聯(lián)吧铺罢。

a、一對(duì)一關(guān)系:

首先残炮,News和Introduction是一對(duì)一的關(guān)系韭赘,那就可以在News類(lèi)中添加如下引用:

public class News {  
    ...  
    //News 和 Intorduction 是一對(duì)一的關(guān)系
    private Introduction introduction;  
      
    // 自動(dòng)生成get、set方法  
}  
  • 就是這么簡(jiǎn)單势就,在News類(lèi)中可以得到一個(gè)對(duì)應(yīng)的Introduction的實(shí)例泉瞻,那么它們之間就是 一對(duì)一關(guān)系 了脉漏。

b、多對(duì)一關(guān)系

  • 接著 Comment和News是多對(duì)一的關(guān)系袖牙,因此 News中應(yīng)該包含多個(gè)Comment侧巨,而Comment中應(yīng)該只有一個(gè)News,所以就可以這樣寫(xiě):
public class News {  
    ......

    //News 和 Intorduction 是一對(duì)一的關(guān)系
    private Intorduction intorduction;

    //News 和 Comment 是一對(duì)多的關(guān)系
    private List<Comment> commentList=new ArrayList<>();
      
    // 自動(dòng)生成get鞭达、set方法  
    ......
}  
  • 先使用 一個(gè)泛型為Comment的List集合來(lái)表示News中包含多個(gè)Comment刃泡,然后修改Comment類(lèi)的代碼,如下所示:
public class Comment {  
    ......

    //Comment 和 News 是多對(duì)一的關(guān)系
    private News news;  
      
    // 自動(dòng)生成get碉怔、set方法   
    ......
}  
  • 在Comment類(lèi)中聲明了一個(gè)News的實(shí)例烘贴,這樣就清楚地表示出了News中可以包含多個(gè)Comment,而Comment中只能有一個(gè)News撮胧,也就是多對(duì)一的關(guān)系了桨踪。

c、多對(duì)多關(guān)系

  • 最后 News和Category是多對(duì)多的關(guān)系芹啥,相信聰明的你一定已經(jīng)知道該怎么寫(xiě)了锻离。News中可以包含多個(gè)Category,所以仍然應(yīng)該使用List集合來(lái)表示:
public class News {  
    ......

    //News 和 Introduction是一對(duì)一關(guān)系
    private Introduction introduction;  
     
    //News 和 Comment是多對(duì)一關(guān)系
    private List<Comment> commentList = new ArrayList<Comment>();  
      
    //News 和 Category是多對(duì)多關(guān)系
    private List<Category> categoryList = new ArrayList<Category>();  
      
    // 自動(dòng)生成get墓怀、set方法 
    ...... 
}  
  • 而Category中也可以包含多個(gè)News汽纠,因此Category類(lèi)也應(yīng)該使用相同的寫(xiě)法,如下所示:
public class Category {  
    ......

    //Category 和 News 是多對(duì)多關(guān)系  
    private List<News> newsList = new ArrayList<News>();  
      
    // 自動(dòng)生成get傀履、set方法
    ......  
} 
  • 這樣就清楚地表達(dá)出它們之間是多對(duì)多的關(guān)聯(lián)了虱朵。

  • 關(guān)聯(lián)關(guān)系都聲明好了之后,我們只需要將所有的實(shí)體類(lèi)都添加到映射列表當(dāng)中钓账,并將數(shù)據(jù)庫(kù)版本號(hào)加1就可以了碴犬。修改litepal.xml的代碼,如下所示:

<?xml version="1.0" encoding="utf-8"?>  
<litepal>  
    <dbname value="demo" ></dbname>  
  
    <version value="4" ></version>  
  
    <list>  
        <mapping class="com.example.databasetest.model.News"></mapping>  
        <mapping class="com.example.databasetest.model.Comment"></mapping>  
        <mapping class="com.example.databasetest.model.Introduction"></mapping>  
        <mapping class="com.example.databasetest.model.Category"></mapping>  
    </list>  
</litepal>  
  • 基本上到這里就可以輕松地說(shuō)結(jié)束了梆暮,現(xiàn)在只需要任意操作一下數(shù)據(jù)庫(kù)服协,表之間的關(guān)聯(lián)關(guān)系就將會(huì)自動(dòng)建立,比如說(shuō)調(diào)用一下Connector.getDatabase()方法啦粹。

  • 下面我們來(lái)驗(yàn)證一下吧偿荷,輸入.table命令查看一下當(dāng)前數(shù)據(jù)庫(kù)中的表,如下所示:


  • OK唠椭,news跳纳、comment、category泪蔫、introduction這幾張表全都有了棒旗,除此之外還有一張category_news中間表。那我們要來(lái)一一檢查一下了,先查看一下introduction表的結(jié)構(gòu)吧铣揉,如下所示:


可以看到饶深,多了一個(gè)news_id列,說(shuō)明introduction表和news表之間的一對(duì)一關(guān)系已經(jīng)建立好了逛拱。

  • 然后再檢查一下comment表的結(jié)構(gòu)敌厘,如下所示:


OK,comment表中也有一個(gè)news_id的列朽合,那么comment表和news表之間的多對(duì)一關(guān)系也已經(jīng)建立好了俱两。

  • 最后檢查一下category_news這張中間表的結(jié)構(gòu),如下所示:


一共只有兩列曹步,一列是news_id宪彩,一列是category_id,分別對(duì)應(yīng)著兩張表的外鍵讲婚,這樣news表和category表的多對(duì)多關(guān)系也建立好了尿孔。

  • 借助LitePal的幫助,即使你并不熟悉數(shù)據(jù)庫(kù)的表關(guān)聯(lián)設(shè)計(jì)筹麸,只要你會(huì)面向?qū)ο缶幊袒詈希伎梢暂p松地將表與表之間的關(guān)聯(lián)建立起來(lái)。創(chuàng)建表物赶、升級(jí)表白指、表關(guān)聯(lián),這就是LitePal在數(shù)據(jù)庫(kù)表管理方面給我們帶來(lái)的巨大便利酵紫,相信大家都能體會(huì)到它的魅力所在了告嘲。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市憨闰,隨后出現(xiàn)的幾起案子状蜗,更是在濱河造成了極大的恐慌需五,老刑警劉巖鹉动,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宏邮,居然都是意外死亡泽示,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)蜜氨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)械筛,“玉大人,你說(shuō)我怎么就攤上這事飒炎÷裼矗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)赤赊。 經(jīng)常有香客問(wèn)我闯狱,道長(zhǎng),這世上最難降的妖魔是什么抛计? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任哄孤,我火速辦了婚禮,結(jié)果婚禮上吹截,老公的妹妹穿的比我還像新娘瘦陈。我一直安慰自己,他們只是感情好波俄,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布晨逝。 她就那樣靜靜地躺著,像睡著了一般懦铺。 火紅的嫁衣襯著肌膚如雪咏花。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天阀趴,我揣著相機(jī)與錄音昏翰,去河邊找鬼。 笑死刘急,一個(gè)胖子當(dāng)著我的面吹牛棚菊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播叔汁,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼统求,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了据块?” 一聲冷哼從身側(cè)響起码邻,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎另假,沒(méi)想到半個(gè)月后像屋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡边篮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年己莺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戈轿。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凌受,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出思杯,到底是詐尸還是另有隱情胜蛉,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站誊册,受9級(jí)特大地震影響奈梳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜解虱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一攘须、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧殴泰,春花似錦于宙、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至离咐,卻和暖如春谱俭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宵蛀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工昆著, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人术陶。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓凑懂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親梧宫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子接谨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容