轉載出處:http://blog.csdn.net/guolin_blog/article/details/40083685
傳統的修改和刪除數據方式
上篇文章中我們已經得知,SQLiteDatabase類中提供了一個insert()方法用於插入數據,那么類似地,它還提供了update()和delete()這兩個方法,分別用於修改和刪除數據。先來看一下update()方法的方法定義:
public int update(String table, ContentValues values, String whereClause, String[] whereArgs)
update()方法接收四個參數,第一個參數是表名,第二個參數是一個封裝了待修改數據的ContentValues對象,第三和第四個參數用於指定修改哪些行,對應了SQL語句中的where部分。
那么比如說我們想把news表中id為2的記錄的標題改成“今日iPhone6發布”,就可以這樣寫:
SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("title", "今日iPhone6發布"); db.update("news", values, "id = ?", new String[] {"2"});
其作用相當於如下SQL語句:
update news set title='今日iPhone6發布' where id=2;
可以看出,比起直接使用SQL語句,update()方法的語義性明顯更強,也更容易讓人理解。
接下來再看一下delete()方法的方法定義:
public int delete(String table, String whereClause, String[] whereArgs)
delete()方法接收三個參數,第一個參數同樣是表名,第二和第三個參數用於指定刪除哪些行,對應了SQL語句中的where部分。
那么比如說我們想把news表中所有沒有評論的新聞都刪除掉,就可以這樣寫:
SQLiteDatabase db = dbHelper.getWritableDatabase(); db.delete("news", "commentcount = ?", new String[] {"0"});
其作用相當於如下SQL語句:
delete from news where commentcount=0;
由此可見,Android給我們提供的這些幫助方法,在很大程度上確實簡化了不少數據庫操作的復雜度。不過LitePal顯然做到了更好,下面就讓我們學習一下如何使用LitePal來進行修改和刪除操作。
使用LitePal修改數據
LitePal修改數據的API比較簡單,並沒有什么太多的用法,也比較好理解,方法都是定義在DataSupport類中的,我們先來看一下方法定義:
public static int update(Class<?> modelClass, ContentValues values, long id)
這個靜態的update()方法接收三個參數,第一個參數是Class,傳入我們要修改的那個類的Class就好,第二個參數是ContentValues對象,這三個參數是一個指定的id,表示我們要修改哪一行數據。
那么比如說我們想把news表中id為2的記錄的標題改成“今日iPhone6發布”,就可以這樣寫:
ContentValues values = new ContentValues(); values.put("title", "今日iPhone6發布"); DataSupport.update(News.class, values, 2);
可以看出,總體來講還是比原生的用法要簡單一些的,首先我們避免掉了要去獲取SQLiteDatabase對象的步驟,其次在指定修改某一條id記錄的時候只需要傳入這個id即可,語法更簡練。
那么有的朋友可能會問了,也許我想修改的是某一個條件下的所有數據,而不是僅僅修改某個id的數據,那該怎么辦呢?別擔心,LitePal還提供了另外一個簡便的方法,方法定義如下:
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);
怎么樣,這種寫法是不是感覺語義性非常強?updateAll()方法在不指定約束條件的情況下就是修改所有行的數據,的的確確是update all了。
當然有些朋友可能會覺得這樣用起來還是有點復雜,因為這個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刪除數據
LitePal刪除數據的API和修改數據是比較類似的,但是更加的簡單一些,我們先來看一下DataSupport類中的方法定義,如下所示:
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的這條記錄作為外鍵的數據一起刪除掉,因為外鍵既然不存在了,那么這么數據也就沒有保留的意義了。
說起來可能有點拗口,我們還是舉例看一下。比如news表中目前有兩條數據,如下圖所示:
然后comment表中也有兩條數據,如下圖所示:
其中comment表中兩條數據的外鍵都是2,指向的news表中id為2的這條記錄。那么下面我們執行如下刪除語句:
int deleteCount = DataSupport.delete(News.class, 2); Log.d("TAG", "delete count is " + deleteCount);
其中delete()方法的返回值表示被刪除的記錄數,打印結果如下所示:
可以看到,有三條記錄被刪除了,那我們再到news表中查詢一下:
OK,只剩下一條記錄了,id為2的那條記錄確實被刪除了。那么再到comment表中看一下呢,如下圖所示:
數據全沒了!為什么呢?因為comment表中的兩條數據都是以news表中id為2的數據作為外鍵的,現在外鍵不存在了,那么這兩條數據自然也沒有存在的意義了,因此被刪除的記錄數一共是3條。這樣是不是就好理解了很多呢?
除了刪除指定id的數據之外,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(); }