主頁: [https://github.com/LitePalFramework/LitePal](https://github.com/LitePalFramework/LitePal)java
配置:android
1. 引入Jar包或源碼git
2. 配置litepal.xmlgithub
在項目的assets目錄下面新建一個litepal.xml文件,並將如下代碼拷貝進去:數據庫
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="demo" ></dbname> <version value="1" ></version> <list> </list> </litepal>
配置文件至關簡單,<dbname>用於設定數據庫的名字,<version>用於設定數據庫的版本號,<list>用於設定全部的映射模型,咱們稍後就會用到編程
3. 配置LitePalApplication數組
因爲操做數據庫時須要用到Context,而咱們顯然不但願在每一個接口中都去傳一遍這個參數,那樣操做數據庫就顯得太繁瑣了。所以,LitePal使用了一個方法來簡化掉Context這個參數,只須要在AndroidManifest.xml中配置一下LitePalApplication,全部的數據庫操做就都不用再傳Context了,以下所示:數據結構
<manifest> <application android:name="org.litepal.LitePalApplication" ... > ... </application> </manifest>
固然,有些程序可能會有本身的Application,並在這裏配置過了。好比說有一個MyApplication,以下所示:app
<manifest> <application android:name="com.example.MyApplication" ... > ... </application> </manifest>
這時只須要修改一下MyApplication的繼承結構,讓它不要直接繼承Application類,而是繼承LitePalApplication類,就可使用一切都能正常工做了,代碼以下所示:框架
public class MyApplication extends LitePalApplication { ... }
可是,有些程序可能會遇到一些更加極端的狀況,好比說MyApplication須要繼承另一個AnotherApplication,而且這個AnotherApplication仍是在jar包當中的,不能修改它的代碼。這種狀況應該算是比較少見了,可是若是你遇到了的話也不用急,仍然是有解釋方案的。你能夠把LitePal的源碼下載下來,而後把src目錄下的全部代碼直接拷貝到你項目的src目錄下面,接着打開LitePalApplication類,將它的繼承結構改爲繼承自AnotherApplication,再讓MyApplication繼承自LitePalApplication,這樣全部的Application就均可以在一塊兒正常工做了。
全部的配置工做所有完成.
建表
LitePal中是如何建表的吧。根據對象關係映射模式的理念,每一張表都應該對應一個模型(Model),也就是說,若是咱們想要建一張news表,就應該有一個對應的News模型類。新建一個News類,而後,表中的每一列其實就是對應了模型類中的一個字段,好比news表中有id、title、content、publishdate、commentcount這幾個列,那麼在News類中就也應該有這幾個字段,代碼以下所示:以下所示:
package com.loaderman.litepaldemo; import java.util.Date; public class News { private int id; private String title; private String content; private Date publishDate; private int commentCount; }
其中id這個字段可寫可不寫,由於即便不寫這個字段,LitePal也會在表中自動生成一個id列,畢竟每張表都必定要有主鍵的嘛。
這裏我要特別說明一下,LitePal的映射規則是很是輕量級的,不像一些其它的數據庫框架,須要爲每一個模型類單獨配置一個映射關係的XML,LitePal的全部映射都是自動完成的。根據LitePal的數據類型支持,能夠進行對象關係映射的數據類型一共有8種,int、short、long、float、double、boolean、String和Date。只要是聲明成這8種數據類型的字段都會被自動映射到數據庫表中,並不須要進行任何額外的配置。
如今模型類已經建好了,咱們還差最後一步,就是將它配置到映射列表當中。編輯assets目錄下的litepal.xml文件,在<list>標籤中加入News模型類的聲明:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="demo" ></dbname> <version value="1" ></version> <list> <mapping class="com.loaderman.litepaldemo.News"></mapping> </list> </litepal>
只要你對數據庫有任何的操做,news表就會被自動建立出來。好比說LitePal提供了一個便捷的方法來獲取到SQLiteDatabase的實例,以下所示:
SQLiteDatabase db = Connector.getDatabase();
調用一下上述代碼,news表就應該已經建立成功
升級表
添加表或者修改字段
須要建立一張comment表。得先建立一個Comment類了,以下所示:
package com.loaderman.litepaldemo; public class Comment { private int id; private String content; }
Comment類中有id和content這兩個字段,也就意味着comment表中會有id和content這兩列。
接着修改litepal.xml中的配置,在映射列表中新增Cooment類,並將版本號加1,以下所示:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="demo" ></dbname> <version value="2" ></version> <list> <mapping class="com.loaderman.litepaldemo.News"></mapping> <mapping class="com.loaderman.litepaldemo.Comment"></mapping> </list> </litepal>
升級的操做就已經完成了,如今咱們只須要操做一下數據庫,comment表就會自動生成了.
若是須要在comment表中添加一個publishdate列,只須要,Comment類中添加這樣一個字段,而後須要在litepal.xml中對版本號加1就好了
這樣當咱們下一次操做數據庫的時候,publishdate列就應該會自動添加到comment表中。調用Connector.getDatabase()方法,而後從新查詢comment表結構
不是說SQLite不支持刪除列的命令嗎?那LitePal又是怎樣作到的呢?其實LitePal並無刪除任何一列,它只是先將comment表重命名成一個臨時表,而後根據最新的Comment類的結構生成一個新的comment表,再把臨時表中除了publishdate以外的數據複製到新的表中,最後把臨時表刪掉。所以,看上去的效果好像是作到了刪除列的功能。
這也是使用框架的好處,若是沒有框架的幫助,咱們顯然不會爲了刪除一個列而大廢周章地去寫這麼多的代碼,而使用框架的話,具體的實現邏輯咱們已經不用再關心,只須要控制好模型類的數據結構就能夠了。
另外,若是你想刪除某一張表的話,操做也很簡單,在litepal.xml中的映射列表中將相應的類刪除,表天然也就不存在了。其它的一些升級操做也都是相似的,相信你已經能觸類旁通,這裏就再也不贅述了。
表關聯
表與表之間的關聯關係一共有三種類型,一對1、多對1、和多對多,
表示兩個表中的數據必須是一一對應的關係。這種場景其實並非很常見,咱們仍是經過例子來直觀地體會一下,
如今已經建立好了news這張表,裏面主要記錄了新聞的標題和內容,那麼除了標題和內容以外,有些新聞還可能帶有一些導語和摘要,咱們把這兩個字段放在一張introduction表中,做爲新聞的簡介。那麼很顯然,news表和introduction表就是一對一的關係了,由於一條新聞只能對應一個簡介,一個簡介也只能屬於一條新聞。它們之間的對應關係大概以下圖描述的同樣:
能夠看到,News1對應了Introduction2,News2對應了Introduction3,News3對應了Introduction1,但無論怎麼樣,它們都是一對一的關係。
因爲數據庫並不像面向對象的語言同樣支持相互引用,若是想讓兩張表之間創建一對一的關係,通常就只能經過外鍵的方式來實現了。所以,一對一關係的表結構就能夠這樣設計:
請注意,introduction表中有一個news_id列,這是一個外鍵列,裏面應該存放一個具體的新聞id,這樣一條introduction就能對應一條news,也就實現一對一的關係了,以下圖所示:
由此咱們就可以看出,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表,它們兩個之間就是典型的多對一關係,一條新聞能夠有不少條評論,可是一條評論只能是屬於一條新聞的。它們的關係以下圖所示:
而這種多對一的關係在編程語言中是很是容易體現出來的,好比Java中就有專門集合類,如List、Set等,使用它們的話就能輕鬆簡單地在對象之間創建多對一的關係,咱們稍後就會看到。那麼,這裏的難點仍然是在數據庫表中如何創建這樣的多對一關係。如今說難點其實已經不難了,由於前面咱們已經學會了一對一關係的創建方法,而多對一也是相似的。沒錯,數據庫表中多對一的關係仍然是經過外鍵來創建的,只不過一對一的時候外鍵加在哪一張表上均可以,但多對一的時候關鍵必需要加在多方的表中。所以,多對一關係的表結構就能夠這樣設計:
在comment表中有一個news_id列,這是一個外鍵列,裏面應該存放一個具體的新聞id,而且容許多條comment都存放同一個新聞id,這樣一條評論就只能對應一條新聞,但一條新聞卻能夠有多條評論,也就實現多對一的關係了,以下圖所示:
由此咱們就能夠看出,id爲一、二、3的三條評論是屬於第一條新聞的,而id爲四、5的兩條評論是屬於第二條新聞的。
表示兩張關聯表中的數據均可以對應另外一張表中的多條數據。這種場景也不算是很常見,但比一對一關係要稍微更加經常使用一些。舉個例子,咱們都知道新聞網站是會將新聞進行種類劃分的,這樣用戶就能夠選擇本身喜歡的那一類新聞進行瀏覽,好比說網易新聞中就會有頭條、科技、娛樂、手機等等種類。每一個種類下面固然都會有許多條新聞,而一條新聞也多是屬於多個種類的,好比iPhone6發佈的新聞既能夠屬於手機種類,也能夠屬於科技種類,甚至還能夠上頭條。所以,新聞和種類之間就是一種多對多的關係,以下圖所示:
能夠看到,News1是屬於Category1的,而News2和News3都是既屬於Category1也屬於Category2,如此複雜的關聯關係該如何表示呢?在面向對象的編程語言中一切都是那麼的簡單,只須要在News類中使用集合類聲明擁有多個Category,而後在Category類中也使用集合類聲明擁有多個News就能夠了,咱們稍後就會看到。而難點仍然是留在了數據庫上,兩張表之間如何創建多對多的關聯關係呢,仍是用外鍵嗎?確定不行了,多對多的狀況只能是藉助中間表來完成了。也就是說,咱們須要多創建一張表,這張表沒什麼其它做用,就是爲了存放news表和category表之間的關聯關係的,以下圖所示:
注意這裏咱們創建一張名爲category_news的中間表,中間表的命名並無什麼強制性的約束,但一個良好的命名規範可讓你一眼就明白這張表是用來作什麼的。中間表裏面只有兩列,並且也只須要有兩列,分別是news表的外鍵和category表的外鍵,在這裏存放新聞和種類相應的id,就可讓它們之間創建關聯關係了,以下圖所示:
由此咱們就能夠看出,第一條新聞是屬於第一個種類的,而第二和第三條新聞,則既屬於第一個種類,也屬於第二個種類。反過來也能夠這樣看,第一個種類下面有第1、第2、第三這三條新聞,而第二個種類下面只有第2、第三這兩條新聞。無論怎麼看,多對多的關係都是成立的。
總結:即一對一關聯的實現方式是用外鍵,多對一關聯的實現方式也是用外鍵,多對多關聯的實現方式是用中間表。
還須要有Introduction和Category這兩個類,新建Introduction類,代碼以下所示:
package com.loaderman.litepaldemo; public class Category { private int id; private String name; }
package com.loaderman.litepaldemo; public class Introduction { private int id; private String guide; private String digest; }
如今四個類都已經建好了,但目前它們都仍是各自獨立的,互相之間沒有任何聯繫,那麼咱們如今就開始用極爲簡單易懂的方式來給它們創建關聯吧。首先,News和Introduction是一對一的關係,那就能夠在News類中添加以下引用:
private Introduction introduction;
就是這麼簡單,在News類中能夠獲得一個對應的Introduction的實例,那麼它們之間就是一對一關係了。
接着Comment和News是多對一的關係,所以News中應該包含多個Comment,而Comment中應該只有一個News,因此就能夠這樣寫:
private List<Comment> commentList = new ArrayList<Comment>();
先使用一個泛型爲Comment的List集合來表示News中包含多個Comment,而後修改Comment類的代碼,以下所示:
private News news;
在Comment類中聲明瞭一個News的實例,這樣就清楚地表示出了News中能夠包含多個Comment,而Comment中只能有一個News,也就是多對一的關係了。
最後News和Category是多對多的關係,相信聰明的你必定已經知道該怎麼寫了。News中能夠包含多個Category,因此仍然應該使用List集合來表示
private List<Category> categoryList = new ArrayList<Category>();
而Category中也能夠包含多個News,所以Category類也應該使用相同的寫法,以下所示:
private List<News> newsList = new ArrayList<News>();
關聯關係都聲明好了以後,咱們只須要將全部的實體類都添加到映射列表當中,並將數據庫版本號加1就能夠了。修改litepal.xml的代碼,以下所示
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="demo" ></dbname> <version value="4" ></version> <list> <mapping class="com.loaderman.litepaldemo.News"></mapping> <mapping class="com.loaderman.litepaldemo.Comment"></mapping> <mapping class="com.loaderman.litepaldemo.Category"></mapping> <mapping class="com.loaderman.litepaldemo.Introduction"></mapping> </list> </litepal>
基本上到這裏就能夠輕鬆地說結束了,如今只須要任意操做一下數據庫,表之間的關聯關係就將會自動創建,好比說調用一下Connector.getDatabase()方法。
查看錶結構發現:
introduction表的結構,多了一個news_id列,說明introduction表和news表之間的一對一關係
comment表的結構comment表中也有一個news_id的列,那麼comment表和news表之間的多對一關係也已經創建好了
category_news這張中間表一共只有兩列,一列是news_id,一列是category_id,分別對應着兩張表的外鍵,這樣news表和category表的多對多關係也創建好了
在項目裏已經建好了News、Comment、Introduction、Category這幾個實體類,經過這些實體類,LitePal就能夠把相應的表自動建立出來。如今來觀察這幾個實體類,咱們發現這幾個類都是沒有繼承結構的。沒錯,由於LitePal進行表管理操做時不須要這些實體類有任何的繼承結構,當時爲了簡單起見就沒有寫。可是進行CRUD操做時就不行了,LitePal要求全部的實體類都要繼承自DataSupport這個類,所以這裏咱們就要把繼承結構給加上才行。修改News類的代碼,以下所示:
能夠看到,這裏只是讓News類繼承自了DataSupport,其它什麼都沒有改變。另外幾個Comment、Introduction、Category類也使用一樣的改法
繼承了DataSupport類以後,這些實體類就擁有了進行CRUD操做的能力,那麼好比想要存儲一條數據到news表當中,就能夠這樣寫
News news = new News(); news.title="這是一條新聞標題"; news.content="這是一條新聞內容"; news.publishDate=new Date(); news.save();
除此以外,save()方法仍是有返回值的,咱們能夠根據返回值來判斷存儲是否成功
save()方法返回的是一個布爾值,用於表示存儲成功仍是失敗,但同時也說明這個方法是不會拋出異常的。有些朋友但願若是存儲失敗的話就拋出異常,而不是返回一個false,那就可使用saveThrows()方法來代替
使用saveThrows()方法來存儲數據,一旦存儲失敗就會拋出一個DataSupportException異常,咱們能夠經過對這個異常進行捕獲來處理存儲失敗的狀況。
LitePal在存儲數據的時候默默幫咱們作了不少的事情,好比多個實體類之間有關聯關係的話,咱們不須要考慮在存儲數據的時候怎麼去創建數據與數據之間的關聯,由於LitePal一切都幫咱們作好了。
仍是經過一個例子來看一下吧,Comment和News之間是多對一的關係,一條News中是能夠包含多條評論的,所以咱們就能夠這樣寫:
Comment comment1 = new Comment(); comment1.setContent("好評!"); comment1.setPublishDate(new Date()); comment1.save(); Comment comment2 = new Comment(); comment2.setContent("贊一個"); comment2.setPublishDate(new Date()); comment2.save(); News news = new News(); news.getCommentList().add(comment1); news.getCommentList().add(comment2); news.setTitle("第二條新聞標題"); news.setContent("第二條新聞內容"); news.setPublishDate(new Date()); news.setCommentCount(news.getCommentList().size()); news.save();
能夠看到,這裏先是存儲了一條comment1數據,而後存儲一條comment2數據,接着在存儲News以前先把剛纔的兩個Comment對象添加到了News的commentList列表當中,這樣就表示這兩條Comment是屬於這個News對象的,最後再把News存儲到數據庫中,這樣它們之間的關聯關係就會自動創建了。
LitePal對集合數據的存儲還專門提供了一個方法,好比說咱們有一個News集合,那麼應該怎樣去存儲這個集合中的每條News呢?傳統狀況下能夠這樣寫:經過一個循環來遍歷出這個集合中的每個News對象,而後逐個調用save()方法。這樣的寫法固然是能夠的,可是效率會比較低,由於調用save()方法的時候除了會執行存儲操做以外,還會去分析News類的關聯關係,那麼每次循環都去從新分析一遍關聯關係顯然是比較耗時的。所以,LitePal提供了一個saveAll()方法,專門用於存儲集合數據的,用法以下所示:
List<News> newsList; ... DataSupport.saveAll(newsList);
saveAll()方法接收一個Collection集合參數,只要把待存儲的集合數據傳入便可。這個方法能夠完成和上面一段代碼徹底同樣的功能,但效率卻會高得多,並且寫法也更加簡單。
LitePal的修改和刪除操做
public static int update(Class<?> modelClass, ContentValues values, long id)
ContentValues values = new ContentValues(); values.put("title", "今日iPhone6發佈"); DataSupport.update(News.class, values, 2);
public static int updateAll(Class<?> modelClass, ContentValues values, String... conditions)
updateAll()方法表示修改多行記錄,其中第一個參數仍然是Class,第二個參數仍是ContentValues對象,第三個參數是一個conditions數組,用於指定修改哪些行的約束條件,返回值表示這次修改影響了多少行數據。好比說咱們想把news表中標題爲「今日iPhone6發佈」的全部新聞的標題改爲「今日iPhone6 Plus發佈」,就能夠這樣寫:
ContentValues values = new ContentValues(); values.put("title", "今日iPhone6 Plus發佈"); DataSupport.updateAll(News.class, values, "title = ?", "今日iPhone6發佈");
重點咱們看一下最後的這個conditions數組,因爲它的類型是一個String數組,咱們能夠在這裏填入任意多個String參數,其中最前面一個String參數用於指定約束條件,後面全部的String參數用於填充約束條件中的佔位符(即?號),好比約束條件中有一個佔位符,那麼後面就應該填寫一個參數,若是有兩個佔位符,後面就應該填寫兩個參數,以此類推。
好比說咱們想把news表中標題爲「今日iPhone6發佈」且評論數量大於0的全部新聞的標題改爲「今日iPhone6 Plus發佈」,就能夠這樣寫:
ContentValues values = new ContentValues(); values.put("title", "今日iPhone6 Plus發佈"); DataSupport.updateAll(News.class, values, "title = ? and commentcount > ?", "今日iPhone6發佈", "0");
能夠看出,經過佔位符的方式來實現條件約束明顯要比原生的API更加簡單易用。
那麼若是咱們想把news表中全部新聞的標題都改爲「今日iPhone6發佈」,該怎麼寫呢?其實這就更簡單了,只須要把最後的約束條件去掉就好了,以下所示:
ContentValues values = new ContentValues(); values.put("title", "今日iPhone6 Plus發佈"); DataSupport.updateAll(News.class, values);
固然有些朋友可能會以爲這樣用起來仍是有點複雜,由於這個ContentValues對象很煩人,每次建立它的時候都要寫不少繁瑣的代碼。不要緊,LitePal也充分考慮了這種狀況,提供了一種不須要ContentValues就能修改數據的方法,下面咱們嘗試使用這種新方法來完成上述一樣的功能。
好比把news表中id爲2的記錄的標題改爲「今日iPhone6發佈」,就能夠這樣寫:
News updateNews = new News(); updateNews.setTitle("今日iPhone6發佈"); updateNews.update(2);
此次咱們並無用ContentValues,而是new出了一個News對象,把要修改的數據直接set進去,最後調用一下update()方法並傳入id就能夠了。不只不用建立ContentValues對象,連表名都不用指定了,由於News對象默認就是修改的news表。
這是其中一種用法,那麼若是咱們想把news表中標題爲「今日iPhone6發佈」且評論數量大於0的全部新聞的標題改爲「今日iPhone6 Plus發佈」,就能夠這樣寫:
News updateNews = new News(); updateNews.setTitle("今日iPhone6發佈"); updateNews.updateAll("title = ? and commentcount > ?", "今日iPhone6發佈", "0");
可是這種用法有一點須要注意,就是若是咱們想把某一條數據修改爲默認值,好比說將評論數修改爲0,只是調用updateNews.setCommentCount(0)這樣是不能修改爲功的,由於即便不調用這行代碼,commentCount的值也默認是0。因此若是想要將某一列的數據修改爲默認值的話,還須要藉助setToDefault()方法。用法也很簡單,在setToDefault()方法中傳入要修改的字段名就能夠了(類中的字段名),好比說咱們想要把news表中全部新聞的評論數清零,就能夠這樣寫:
News updateNews = new News(); updateNews.setToDefault("commentCount"); updateNews.updateAll();
使用LitePal刪除數據
public static int delete(Class<?> modelClass, long id)
delete()方法接收兩個參數,第一個參數是Class,傳入咱們要刪除的那個類的Class就好,第二個參數是一個指定的id,表示咱們要刪除哪一行數據。
那麼好比說咱們想刪除news表中id爲2的記錄,就能夠這樣寫:
DataSupport.delete(News.class, 2);
須要注意的是,這不只僅會將news表中id爲2的記錄刪除,同時還會將其它表中以news id爲2的這條記錄做爲外鍵的數據一塊兒刪除掉,由於外鍵既然不存在了,那麼這麼數據也就沒有保留的意義了。
DataSupport中也提供了一個經過where語句來批量刪除數據的方法,先看一下方法定義:
public static int deleteAll(Class<?> modelClass, String... conditions)
看起來很眼熟吧?很是簡單,deleteAll()方法接收兩個參數,第一個參數是Class,傳入咱們要刪除的那個類的Class就好,第二個參數是一個conditions數組,用於指定刪除哪些行的約束條件,返回值表示這次刪除了多少行數據,用法和updateAll()方法是基本相同的。
那麼好比說咱們想把news表中標題爲「今日iPhone6發佈」且評論數等於0的全部新聞都刪除掉,就能夠這樣寫:
DataSupport.deleteAll(News.class, "title = ? and commentcount = ?", "今日iPhone6發佈", "0");
而若是咱們想把news表中全部的數據所有刪除掉,就能夠這樣寫:
DataSupport.deleteAll(News.class);
在不指定約束條件的狀況下,deleteAll()方法就會刪除表中全部的數據了
除了DataSupport類中提供的靜態刪除方法以外,還有一個刪除方法是做用於對象上的,即任何一個繼承自DataSupport類的實例均可以經過調用delete()這個實例方法來刪除數據。但前提是這個對象必定是要持久化以後的,一個非持久化的對象若是調用了delete()方法則不會產生任何效果
好比說下面這種寫法:
News news = new News(); news.delete();
這裏new出了一個News對象,這個對象明顯是沒有持久化的,那麼此時調用delete()方法則不會刪除任何數據。但若是咱們以前將這個對象持久化過了,那麼再調用delete()方法就會把這個對象對應的數據刪除掉了,好比:
News news = new News(); news.setTitle("這是一條新聞標題"); news.setContent("這是一條新聞內容"); news.save(); ... news.delete();
一個對象若是save過了以後,那就是持久化的了。除了調用save()方法以外,經過DataSupport中提供的查詢方法從數據庫中查出來的對象也是通過持久化的,查詢的功能咱們會在下篇博客中講解。
另外還有一個簡單的辦法能夠幫助咱們判斷一個對象是不是持久化以後的,DataSupport類中提供了一個isSaved()方法,這個方法返回true就表示該對象是通過持久化的,返回false則表示該對象未通過持久化。那麼刪除一個對象對應的數據也就能夠這樣寫了:
News news; ... if (news.isSaved()) { news.delete(); }
查詢
查詢news表中id爲1的這條記錄,使用LitePal就能夠這樣寫
News news = DataSupport.find(News.class, 1);
想要獲取news表中的第一條數據,只須要這樣寫:
News firstNews = DataSupport.findFirst(News.class);
想要獲取News表中的最後一條數據:
News lastNews = DataSupport.findLast(News.class);
news表中id爲一、三、五、7的數據都查出來,這時候用findAll()。這個方法的用法和find()方法是很是相似的,只不過它能夠指定多個id,而且返回值也再也不是一個泛型類對象,而是一個泛型類集合,以下所示:
List<News> newsList = DataSupport.findAll(News.class, 1, 3, 5, 7);
能夠看到,首先咱們是調用的findAll()方法,而後這個方法的第一個參數仍然是指定的泛型類,可是後面的參數就很隨意了,你能夠傳入任意個id進去,findAll()方法會把全部傳入的id所對應的數據所有查出來,而後一塊兒返回到List<News>這個泛型集合當中。
雖然說這個語法設計算是至關人性化,可是在有些場景或許不太適用,由於可能要你要查詢的多個id已經封裝到一個數組裏了。那麼不要緊,findAll()方法也是接收數組參數的,因此說一樣的功能你也能夠這樣寫:
long[] ids = newlong[] { 1, 3, 5, 7 }; List<News> newsList = DataSupport.findAll(News.class, ids);
查詢全部數據的寫法更簡單,只須要這樣寫:
List<News> allNews = DataSupport.findAll(News.class);
連綴查詢:
這種查詢很靈活,能夠根據咱們實際的查詢需求來動態配置查詢參數。 那這裏舉個簡單的例子,好比咱們想查詢news表中全部評論數大於零的新聞,就能夠這樣寫:
List<News> newsList = DataSupport.where("commentcount > ?", "0").find(News.class);
能夠看到,首先是調用了DataSupport的where()方法,在這裏指定了查詢條件。where()方法接收任意個字符串參數,其中第一個參數用於進行條件約束,從第二個參數開始,都是用於替換第一個參數中的佔位符的。那這個where()方法就對應了一條SQL語句中的where部分。
接着咱們在where()方法以後直接連綴了一個find()方法,而後在這裏指定一個泛型類,表示用於查詢哪張表。那麼上面的一段代碼,查詢出的結果和以下SQL語句是相同的:
select * from users where commentcount > 0;
可是這樣會將news表中全部的列都查詢出來,也許你並不須要那麼多的數據,而是隻要title和content這兩列數據。那麼也很簡單,咱們只要再增長一個連綴就好了,以下所示:
List<News> newsList = DataSupport.select("title", "content") .where("commentcount > ?", "0").find(News.class);
能夠看到,這裏咱們新增了一個select()方法,這個方法接收任意個字符串參數,每一個參數要求對應一個列名,這樣就只會把相應列的數據查詢出來了,所以select()方法對應了一條SQL語句中的select部分。
那麼上面的一段代碼,查詢出的結果和以下SQL語句是相同的:
select title,content from users where commentcount > 0;
好比說,我但願將查詢出的新聞按照發布的時間倒序排列,即最新發布的新聞放在最前面,那就能夠這樣寫:
List<News> newsList = DataSupport.select("title", "content") .where("commentcount > ?", "0") .order("publishdate desc").find(News.class);
order()方法中接收一個字符串參數,用於指定查詢出的結果按照哪一列進行排序,asc表示正序排序,desc表示倒序排序,所以order()方法對應了一條SQL語句中的order by部分。
那麼上面的一段代碼,查詢出的結果和以下SQL語句是相同的:
select title,content from users where commentcount > 0 orderby publishdate desc;
而後呢,也許你並不但願將全部條件匹配的結果一次性所有查詢出來,由於這樣數據量可能會有點太大了,而是但願只查詢出前10條數據,那麼使用連綴一樣能夠輕鬆解決這個問題,代碼以下所示:
List<News> newsList = DataSupport.select("title", "content") .where("commentcount > ?", "0") .order("publishdate desc").limit(10).find(News.class);
那麼上面的一段代碼,查詢出的結果和以下SQL語句是相同的:
select title,content from users where commentcount > 0 order by publishdate desc limit 10;
剛纔咱們查詢到的是全部匹配條件的前10條新聞,那麼如今我想對新聞進行分頁展現,翻到第二頁時,展現第11到第20條新聞,這又該怎麼實現呢?不要緊,在LitePal的幫助下,這些功能都是十分簡單的,只須要再連綴一個偏移量就能夠了,以下所示:
List<News> newsList = DataSupport.select("title", "content") .where("commentcount > ?", "0") .order("publishdate desc").limit(10).offset(10) .find(News.class);
能夠看到,這裏咱們又添加了一個offset()方法,用於指定查詢結果的偏移量,這裏指定成10,就表示偏移十個位置,那麼原來是查詢前10條新聞的,偏移了十個位置以後,就變成了查詢第11到第20條新聞了,若是偏移量是20,那就表示查詢第21到第30條新聞,以此類推。所以,limit()方法和offset()方法共同對應了一條SQL語句中的limit部分。
那麼上面的一段代碼,查詢出的結果和以下SQL語句是相同的:
select title,content from users where commentcount > 0 orderby publishdate desc limit 10,10;
激進查詢
不過,上述咱們的全部用法中,都只能是查詢到指定表中的數據而已,關聯表中數據是沒法查到的,由於LitePal默認的模式就是懶查詢,固然這也是推薦的查詢方式。那麼,若是你真的很是想要一次性將關聯表中的數據也一塊兒查詢出來,固然也是能夠的,LitePal中也支持激進查詢的方式,下面咱們就來一塊兒看一下。
不知道你有沒有發現,剛纔咱們所學的每個類型的find()方法,都對應了一個帶有isEager參數的方法重載,這個參數相信你們一看就明白是什麼意思了,設置成true就表示激進查詢,這樣就會把關聯表中的數據一塊兒查詢出來了。
好比說,咱們想要查詢news表中id爲1的新聞,而且把這條新聞所對應的評論也一塊兒查詢出來,就能夠這樣寫:
News news = DataSupport.find(News.class, 1, true); List<Comment> commentList = news.getCommentList();
能夠看到,這裏並無什麼複雜的用法,也就是在find()方法的最後多加了一個true參數,就表示使用激進查詢了。這會將和news表關聯的全部表中的數據也一塊兒查出來,那麼comment表和news表是多對一的關聯,因此使用激進查詢一條新聞的時候,那麼該新聞所對應的評論也就一塊兒被查詢出來了。
激進查詢的用法很是簡單,就只有這麼多,其它find()方法也都是一樣的用法,就再也不重複介紹了。可是這種查詢方式LitePal並不推薦,由於若是一旦關聯表中的數據不少,查詢速度可能就會很是慢。並且激進查詢只能查詢出指定表的關聯表數據,可是無法繼續迭代查詢關聯表的關聯表數據。所以,這裏我建議你們仍是使用默認的懶加載更加合適,至於如何查詢出關聯表中的數據,其實只須要在模型類中作一點小修改就能夠了。修改News類中的代碼,以下所示:
public class News extends DataSupport{ ... public List<Comment> getComments() { return DataSupport.where("news_id = ?", String.valueOf(id)).find(Comment.class); } }
能夠看到,咱們在News類中添加了一個getComments()方法,而這個方法的內部就是使用了一句連綴查詢,查出了當前這條新聞對應的全部評論。改爲這種寫法以後,咱們就能夠將關聯表數據的查詢延遲,當咱們須要去獲取新聞所對應的評論時,再去調用News的getComments()方法,這時纔會去查詢關聯數據。這種寫法會比激進查詢更加高效也更加合理。
相信你已經體會到,LitePal在查詢方面提供的API已經至關豐富了。可是,也許你總會遇到一些千奇百怪的需求,可能使用LitePal提供的查詢API沒法完成這些需求。沒有關係,由於即便使用了LitePal,你仍然可使用原生的查詢方式(SQL語句)來去查詢數據。DataSuppport類中還提供了一個findBySQL()方法,使用這個方法就能經過原生的SQL語句方式來查詢數據了,以下所示:
Cursor cursor = DataSupport.findBySQL("select * from news where commentcount>?", "0");
findBySQL()方法接收任意個字符串參數,其中第一個參數就是SQL語句,後面的參數都是用於替換SQL語句中的佔位符的,用法很是簡單。另外,findBySQL()方法返回的是一個Cursor對象,這和原生SQL語句的用法返回的結果也是相同的。
使用LitePal的聚合函數
LitePal中一共提供了count()、sum()、average()、max()和min()這五種聚合函數,基本上已經將SQL語句當中最經常使用的幾種聚合函數都覆蓋了,那麼下面咱們就來對這五種聚合函數的用法
count()方法主要是用於統計行數的,剛纔演示瞭如何經過SQL語句來統計news表中一共有多少行,那麼下面咱們來看一下如何經過LitePal來實現一樣的功能,代碼以下所示:
int result = DataSupport.count(News.class);
你沒有看錯!就是這樣一行代碼就能夠了。調用DataSupport類當中的count()方法,count()方法接收一個Class參數,用於指定去統計哪張表當中的數據,而後返回值是一個整型數據,也就是統計出的結果了。
除此以外,LitePal中全部的聚合函數都是支持連綴的,也就是說咱們能夠在統計的時候加入條件語句。好比說想要統計一共有多少條新聞是零評論的,就能夠這樣寫:
int result = DataSupport.where("commentcount = ?", "0").count(News.class);
這個用法和咱們在上一篇文章當中學到的連綴查詢是比較像的,在DataSupport類中首先指定一個where語句用於條件約束,而後連綴一個count()方法,這樣統計出的就是知足條件語句的結果了。連綴不只適用於count()方法,也一樣適用於下面咱們將要介紹的全部方法,但因爲用法都是相同的,後面就再也不重複介紹了。
看完了count()方法應該是以爲很是簡單吧,剩下的幾個聚合函數也是一樣簡單的,咱們繼續來學習一下。
sum()方法主要是用於對結果進行求合的,好比說咱們想要統計news表中評論的總數量,就能夠這樣寫:
int result = DataSupport.sum(News.class, "commentcount", int.class);
sum()方法的參數要稍微多一點,咱們來一一看下。第一個參數很簡單,仍是傳入的Class,用於指定去統計哪張表當中的數據。第二個參數是列名,表示咱們但願對哪個列中的數據進行求合。第三個參數用於指定結果的類型,這裏咱們指定成int型,所以返回結果也是int型。
須要注意的是,sum()方法只能對具備運算能力的列進行求合,好比說整型列或者浮點型列,若是你傳入一個字符串類型的列去求合,確定是得不到任何結果的,這時只會返回一個0做爲結果。
average()方法主要是用於統計平均數的,好比說咱們想要統計news表中平均每條新聞有多少評論,就能夠這樣寫:
double result = DataSupport.average(News.class, "commentcount");
其中average()方法接收兩個參數,第一個參數不用說,仍然是Class。第二個參數用於指定列名的,表示咱們想要統計哪一列的平均數。須要注意的是,這裏返回值的類型是double型,由於平均數基本上都是會帶有小數的,用double類型能夠最大程序保留小數位的精度。
一樣地,average()方法也只能對具備運算能力的列進行求平均值,若是你傳入了一個字符串類型的列,也是沒法獲得任何結果的,這時一樣只會返回一個0做爲結果。
max()方法主要用於求出某個列中最大的數值,好比咱們想要知道news表中全部新聞裏面最高的評論數是多少,就能夠這樣寫:
int result = DataSupport.max(News.class, "commentcount", int.class);
能夠看到,max()方法接收三個參數,第一個參數一樣仍是Class,用於指定去統計哪張表當中的數據。第二個參數是列名,表示咱們但願統計哪一個列中的最大值。第三個參數用於指定結果的類型,根據實際狀況來選擇傳入哪一種類型就好了。
那麼不用多說,max()方法也只能對具備運算能力的列進行求最大值的,但願你在使用的時候可以謹記這一點。
min()方法主要用於求出某個列中最小的數值,好比咱們想要知道news表中全部新聞裏面最少的評論數是多少,就能夠這樣寫:
int result = DataSupport.min(News.class, "commentcount", int.class);
min()方法和max()方法的用法基本上是如出一轍的,參數也是徹底相同,只是方法名變了一下。它們一個是求出某一列中的最大值,一個是求出某一列中的最小值,僅此而已。
News news; ... if (news.isSaved()) { news.delete(); }