LitePal——Android數據庫框架,修煉的三重境界,你到第幾層了?

LitePal是一款開源的Android數據庫框架,採用了ORM對象關係映射的模式,將常用的數據庫功能進行了封裝。是大名鼎鼎郭神的傑作。
下面我主要分三重境界來講解:咋用?咋關聯?咋增刪改查?適合各個層次的人用來進一步更深入地瞭解和應用LitePal,下面開始正題…

第一重境界:LitePal咋用????

第一重境界一定要認真閱讀郭神的《Android數據庫高手祕籍》,上下共八篇,下面是第零篇的鏈接
http://blog.csdn.net/sinyu890807/article/details/38083103,讓我們一起來好生閱讀,然後再來讀本文的總結,就有望早日突破三界之外…

1.在AndroidStudio中的moudle的buildgradle中添加依賴:

dependencies {
    compile 'org.litepal.android:core:1.3.2'
}

2.在Project目錄結構的main下建立assets文件夾,並在assets下創建litepal.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <dbname value="demo"></dbname>
    <version value="1"></version>
    <list>
    </list>
</litepal>

3.在清單文件中加入LitePalApplication的申明:

<manifest>
    <application
        name="org.litepal.LitePalApplication"
        ...
        >
    ...
    </application>
</manifest>

注:1),如果用到了自定義的Application,只需要將自定義的Application繼承LitePalApplication。
2),如果必須要繼承第三方Jar包裏的Application,可以將litePal的源碼下載然後添加到項目中,然後修改LitePalApplication繼承第三方Jar包的Application,然後自定義的Application再繼承LitePalApplication就OK了。

4.根據對象關係映射模式的概念,每一張表應該對應一個模型,比如說要建一張新聞類的News表,可以這樣:

public class News extends DataSupport{//繼承關係不可少
    private int id;         // 可以不寫,LitePalace會自定生成
    private String title;
    private String content;
    private Date publishDate;
    private int commentCount;
    // getter、setter
}

注:1).映射的數據類型一共有8種:int、short、long、float、double、boolean、String和Date ;
2).使用LitePal只有聲明private的字段纔會被映射到數據表中,如果不想映射的話,修飾符設置爲public、protected、default就可以了。
3).必須要繼承DataSupport,不能忘 。

5.在litepal.xml文件中加入模型類的申明:

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

6.在入口Activity或者自定義的Application的onCreate()方法中獲取SQLiteDatabase的實例,就可以執行建表邏輯了,如下:

SQLiteDatabase db = Connector.getDatabase();

7.使用LitePal升級表的時候,比如說加減列,增刪表,都可以通過操作Model來間接操作表,然後在 litepal.xml 中的增加數據庫的版本就好了:

<?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 class="com.example.databasetest.model.Comment"/>
        </list>
</litepal>

第二重境界:LitePal咋建關聯表?????

個人理解:LitePal其實是用model來映射表,只需要考慮model與model的關聯關係,litepal會由此自動生成表的關聯關係,不用我們考慮表的關關聯。

下面就來將郭神在八篇數據庫裏面的四張表(),堆在這裏來說明一對一,多對一,多對多三種關聯表,重點是多對一的情況。

首先是新聞類News,對應News表:


public class News extends DataSupport{

    private int id;
    private String title;
    private String content;
    private int commentCount;
    private Date publishDate;

    //News和Introdection是一對一的關係:1/1步到位
    private Interduction interduction;
    //News和Comment是多對一的關係:1/2步
    private List<Comment> commentList=new ArrayList<>();
    //News和Category是多對多的關係:1/2步
    private List<Category> categoryList=new ArrayList<>();

    //自動生成getter,setter方法

}

然後是簡介表Introdection,對應Introdection表,它和News是一對一的關係:

public class Interduction extends DataSupport{

    private int id;
    private String guide;
    private String digest;
    //private News news;//這裏和News表中的Introdection對象,二選一保留均可
    //自動生成getter,setter方法
}

接下來是Comment,對應的是Comment表,它和News是多對一的關係:

public class Comment extends DataSupport{

    private int id;
    private String content;
    private Date publishDate;
    //Comment和News是多對一的關係:2/2步
    private News news;
    //自動生成getter,setter方法
}

最後是類別類Category,對應Category表,它和News是多對多的關係:

public class Category extends DataSupport{

    private int id;
    private String name;
    //News和Category是多對多的關係:2/2步
    private List<News> newsList=new ArrayList<>();

    //自動生成getter,setter方法

}

如此四個model,既有各model之間的關係又在內部暗含四張表的關聯關係。這樣寫十分便宜,如果讀者看不明白,真心希望讀者去看郭神自己的介紹。。。

第三重境界:LitePal的增刪改查

1.增加數據:

  private void saveNews(){
        News news = new News();
        news.setTitle("這是一條新聞標題");
        news.setContent("這是一條新聞內容");
        news.setPublishDate(new Date());
        Log.d("TAG", "news id is " + news.getId());//輸出是0,id字段此時還沒有賦值
        if (news.save()) {
            Log.d("TAG", "news id is " + news.getId());//輸出是1,id字段此時才賦值:數據庫第一條數據的主鍵id是從1開始的
            Toast.makeText(this, "存儲成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "存儲失敗", Toast.LENGTH_SHORT).show();
        }
        //或者可以使用當 save()方法返回false時能拋出異常的saveThrows();

    }

2.增加數據集合:

private void saveList(){

        List<News> newsList=new ArrayList<>();
        //...
        //傳統的存儲方式:一個一個存
        //for (News news : newsList) {
        //    news.save();
        //}

        //LitePal存儲方式:直接存集合
        DataSupport.saveAll(newsList);

    }

3.關聯表存儲,eg:多對一存儲。

private void saveMutiToOne(){
        Comment comment = new Comment();
        comment.setContent("好評!");
        comment.setPublishDate(new Date());
        // 1/3步:先將comment存儲到Comment表
        comment.save();

        Comment comment2 = new Comment();
        comment2.setContent("贊一個");
        comment2.setPublishDate(new Date());
        comment2.save();

        News news = new News();
        // 2/3步:通過下面的方法將comment和news數據經行多對一關聯:外鍵關聯在這裏設置
        news.getCommentList().add(comment);
        news.getCommentList().add(comment2);
        news.setTitle("第二條新聞標題");
        news.setContent("第二條新聞內容");
        news.setPublishDate(new Date());
        news.setCommentCount(news.getCommentList().size());
        // 3/3步:將news對象存儲到News表中:外鍵在這裏成功關聯
        news.save();       
    }

注 :1). 內行的朋友肯定會知道多對一是通過外鍵經行存儲的,但是這裏我們並沒有指定任何外鍵,原因大概是:LitePal的外鍵是託管的或者說是自動設置的,這個時候當調用news的save方法時,LitePal會爲該條news添加正確的id,然後會將此id自動存放到兩個comment對應的外鍵列上,從而完成了通過外鍵經行數據的關聯。
2). 口訣:一對一 ,多對一,通過外鍵關聯,多對多通過中間表關聯
3). 我們不需要考慮在存儲數據的時候怎麼去建立數據與數據之間的關聯,因爲LitePal一切都幫我們做好了。而多對多或者是一對一也是同理。

4.修改數據:

private void updateData(){
        //一/,使用ContentValues經行數據的修改

            //1/修改指定某行某列的數據
            ContentValues values = new ContentValues();
            values.put("title", "今日iPhone6發佈");
            DataSupport.update(News.class, values, 2);

            //2/根據限定條件修改多行的某列數據
            ContentValues values1 = new ContentValues();
            values1.put("title", "今日iPhone6發佈");
            DataSupport.updateAll(News.class, values1, "title = ?", "今日iPhone16發佈");
            //3/當多個限定條件時該這樣寫
            DataSupport.updateAll(News.class, values, "title = ? and commentcount > ?", "今日iPhone6發佈", "0");
            //4/當沒有約束條件修改表中所有行的某列數據
            DataSupport.updateAll(News.class, values);

        //二/如果不想使用ContentValues可以使用Model對象

            //1/修改指定某行某列的數據:
            News updateNews = new News();
            updateNews.setTitle("今日iPhone6發佈");
            updateNews.update(2);

            //2/當多個限定條件修改多行的某列數據時該這樣寫
            News updateNews2 = new News();
            updateNews2.setTitle("今日iPhone6發佈");
            updateNews2.updateAll("title = ? and commentcount > ?", "今日iPhone6發佈", "0");

            //3/當將所有行某列的數據設置成默認值時:只能用下面的方法
            News updateNews3 = new News();
            updateNews3.setToDefault("commentCount");
            updateNews3.updateAll();
    }
  1. 刪除數據:與修改數據相似
private void deleteData(){

        //1/刪除某行數據:會一同刪除與此條數據有外鍵關係的所有數據
        DataSupport.delete(News.class, 2);//該方法返回int類型:一共刪除了多少條數據

        //2/指定條件刪除多行數據
        DataSupport.deleteAll(News.class, "title = ? and commentcount = ?", "今日iPhone6發佈", "0");

        //3/刪除表中所有數據
        DataSupport.deleteAll(News.class);

        //4/刪除已經儲存的數據
        News news = new News();
        news.setTitle("這是一條新聞標題");
        news.setContent("這是一條新聞內容");
        news.save();
        //...
        news.delete();

        //5/判斷一條數據是否持久化(存儲過)
        if (news.isSaved()) {
            news.delete();
        }
    }

6.查詢數據:

 private void queryData(){

        //1/查詢指定行的數據
        News news = DataSupport.find(News.class, 1);

        //2/查詢第一行或最後一行的數據
        News firstNews = DataSupport.findFirst(News.class);
        News lastNews = DataSupport.findLast(News.class);

        //3/查詢指定多行數據
        List<News> newsList = DataSupport.findAll(News.class, 1, 3, 5, 7);

        //4/查詢行號組成的數組裏面的多行數據
        long[] ids = new long[] { 1, 3, 5, 7 };
        List<News> newsList2 = DataSupport.findAll(News.class, ids);

        //5/查詢某表所有行的數據
        List<News> allNews = DataSupport.findAll(News.class);

        //6/根據某列的約束條件經行查詢
        List<News> newsList3 = DataSupport.where("commentcount > ?", "0").find(News.class);

        //7/根據返回集合多列需求經行約束條件查詢(如下:只需要title和content兩列數據)
        List<News> newsList4 = DataSupport.select("title", "content")
                .where("commentcount > ?", "0").find(News.class);

        //8/根據返回集合排序需求經行約束條件查詢(如下:根據發佈時間倒序排序)asc表示正序排序,desc表示倒序排序
        List<News> newsList5 = DataSupport.select("title", "content")
                .where("commentcount > ?", "0")
                .order("publishdate desc").find(News.class);

        //9/根據返回集合限制數量需求經行約束條件查詢
        List<News> newsList6= DataSupport.select("title", "content")
                .where("commentcount > ?", "0")
                .order("publishdate desc").limit(10).find(News.class);
        //10/根據返回集合指定起始需求經行約束條件查詢
        List<News> newsList7 = DataSupport.select("title", "content")//指定列
                .where("commentcount > ?", "0")//約束條件
                .order("publishdate desc")//正序排列
                .limit(10)//共需要10條數據
                .offset(10)//第10條數據開始
                .find(News.class);//指定表

        //11/連帶關聯表中的數據進行激進查詢
        News news0 = DataSupport.find(News.class, 1, true);
        List<Comment> commentList = news.getCommentList();

        //12/查詢時不推薦使用激進查詢,如果確實需要可以在Model表中添加這樣的方法
//        public class News extends DataSupport{
//
//            ...
//
//            public List<Comment> getComments() {
//                return DataSupport.where("news_id = ?", String.valueOf(id)).find(Comment.class);
//            }
//
//        }

    }

7.聚合函數:

private void togetherMeath(){

        //1/count()方法就是用於統計行數
        int result = DataSupport.count(News.class);
        //2/約束條件統計行數
        int result1 = DataSupport.where("commentcount = ?", "0").count(News.class);

        //3/sum()方法主要是用於對結果進行求和的(限:整型,浮點型可用,其他類型(如字符串)不可用放回0)
        int result2 = DataSupport.sum(News.class, "commentcount", int.class);

        //4/max()方法主要是求出某個列的最大的數值(限:整型,浮點型可用)
        int result3 = DataSupport.max(News.class, "commentcount", int.class);
        //5/max()方法主要是求出某個列的最大的數值(限:整型,浮點型可用)
        int result4= DataSupport.min(News.class, "commentcount", int.class);
    }

附錄:查詢,修改boolean值得相關問題:

1).查詢boolean類型的列:boolean在賦值都是true或false,但是實際存儲時,存在數據庫的爲1或0,所以查詢時查詢參數應該爲1和0,而不是true和false。

    // 錯誤的寫法
    // List<Phone> noPowerPhones = DataSupport.where("power = ?", “false”).find(Phone.class);
    // 正確的寫法
    List<Phone> noPowerPhones = DataSupport.where("power = ?", “0”).find(Phone.class);

2).修改boolean類型默認:boolean類型的字段在設置爲真時就是是賦值true,以及使用setToDefault()方法

  News updateNews = new News();
  updateNews.setToDefault("isRead");
  updateNews.updateAll();

自己拿個鏡子照照自己,自己修煉到幾重境界了。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章