Android数据库高手秘籍(六)——LitePal的修改和删除操作

1,245 阅读11分钟

在上一篇文章中,我们学会了使用 LitePal 进行存储数据的功能。确实,比起直接使用 Android 原生的 API,LitePal 明显简单方便了太多。那么,在增删改查四种操作中,我们已经把 “增” 学完了,今天就让我们继续趁热打铁,学习一下如何使用 LitePal 进行修改和删除操作。还没有看过前一篇文章的朋友建议先去参考 Android 数据库高手秘籍 (五)——LitePal 的存储操作

LitePal 的项目地址是:github.com/LitePalFram…

传统的修改和删除数据方式

上篇文章中我们已经得知,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();
}

好了,这样我们就把 LitePal 中提供的修改和删除数据操作的用法基本都学习完了,那么今天的文章就到这里,下一篇文章中会开始讲解查询数据的用法,感兴趣的朋友请继续阅读 [Android 数据库高手秘籍 (七)——体验 LitePal 的查询艺术]

关注我的技术公众号”郭霖“,每天都有优质技术文章推送。