Working with databases
Cupboard 的核心目标是从 SQLiteDatabase 中存取对象。 本章就描述如何使用最少的 SQL 来操作 database。 在 Android 开发中,通常使用 SQLiteOpenHelper 来创建和管理数据库连接,但不论是从 SQLiteOpenHelper 还是从其他地方(第三方)获取的 SQLiteDatabase 引用, 本章的内容都同样适用。
操作数据库从 withDatabase() 开始。
创建数据库/Setting up the database
在使用 Cupboard 之前,需要事先将待操作的 entity 注册到 Cupboard,推荐在 SQLiteOpenHelper 的静态初始化块中来进行注册:
import static nl.qbusict.cupboard.CupboardFactory.cupboard;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class CupboardSQLiteOpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "myapp.db";
private static final int DATABASE_VERSION = 1;
static {
// 注册 model
cupboard().register(Book.class);
cupboard().register(Author.class);
}
public CupboardSQLiteOpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 创建 table
cupboard().withDatabase(db).createTables();
// ...其他语句
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 升级 tables,添加 col,创建新表
// 注意,已经存在的 col 不会被转换
cupboard().withDatabase(db).upgradeTables();
// ...迁移数据
}
}
注:不需要继承或者重写任何东西,这就是一个标准的 SQLiteOpenHelper,只不过在其中增加了几个 Cupboard 调用而已。 如果你正在使用 SQLiteOpenHelper,集成 Cupboard 就非常容易了。
首先,静态导入 Cupboard,在静态初始块中注册 entity,然后你就可以使用下面的语句来创建或者更新数据库:
创建:
cupboard().withDatabase(db).createTables();
更新:
cupboard().withDatabase(db).upgradeTables();
即使你并没有使用 SQLiteOpenHelper,你仍然需要使用 register() 来注册 entity,同时使用 createTables() 或者 updateTables() 来建立数据库。
保存对象/Storing objects
你的 model 必须定义一个 Long 类型的 _id 字段。
(译者:即使不定义也没有关系,只不过 _id 是 Android 数据库的最佳实践,所以还是加上比较好。另外, _id 不一定要 Long 类型, long也可以,不过 Long 可以取值为 null,long 类型却不行)
要保存一个对象,只需要调用 withDatabase(db).put() 即可 :
Book book = ...
long id = cupboard().withDatabase(db).put(book);
如果 book 有 _id 属性,那么,数据库中与 _id 匹配的记录都会被替换,如果 _id 为 null,那么一个新的 book 记录就会被创建。无论是哪种情况,put()都会返回对应的记录 id。
获取对象/Getting objects
通过 id 获取对象也很简单:
Book book = cupboard().withDatabase(db).get(Book.class, 12L);
上面的语句返回 id 为 12 的记录,没有则返回 null。
如果要查询 book 集合,使用 query()
// 获取第一条结果
Book book = cupboard().withDatabase(db).query(Book.class).get();
// 获取查询游标
Cursor books = cupboard().withDatabase(db).query(Book.class).getCursor();
try {
// Iterate books
QueryResultIterable<Book> itr = cupboard().withDatabase(db).query(Book.class).query().iterator();
/**
* 译者:原始文档有误,原始文档是 QueryResultIterable<Book> itr = cupboard().withDatabase(db).query(Book.class).iterate(); 调用错误
应该是原作者笔误,或者没有更新文档。
*/
for (Book book : itr) {
// do something with book
}
} finally {
// close the cursor
itr.close();
}
// Get the first matching book with title Android
Book book = cupboard().withDatabase(db).query(Book.class).withSelection("title = ?", "Android").get();
query() 的返回值可以是单个 entity,也可以是 entity 的迭代器,或者是一个 Cursor。
更新对象/Updating objects
使用 put() 可以整体替换或者更新一个 entity。但是如果你只是想部分更新一个 entity,或者一次性更新多个 entity,你可以使用 update()。 通常,这在 ContentProvider 中获取 ContentValues 的时候用得比较多。
(译者:put 一次只能更新单个记录, update 可以更新很多)
ContentValues values = new ContentValues(1);
values.put("title", "Android")
// update all books where the title is 'android'
cupboard().withDatabase(db).update(Book.class, values, "title = ?", "android");
删除对象/Deleting objects
删除操作与 put() 和 get() 一样简单。
// by id
cupboard().withDatabase(db).delete(Book.class, 12L);
// by passing in the entity
cupboard().withDatabase(db).delete(book);
// or by selection
cupboard().withDatabase(db).delete(Book.class, "title = ?", "android");
// delete all entries in a given table
cupboard().withDatabase(db).delete(Book.class, null);
Tips and tricks
Entity转ContentValues/Entity to ContentValues
如果你需要直接操作 SQLiteDatabase,你可以将任意已注册的 entity 转换为 ContentValues:
ContentValues values = cupboard().withEntity(Book.class).toContentValues(book);
// you can also reuse ContentValues
values = cupboard().withEntity(Book.class).toContentValues(book, values);
Cursor转Entity/Cursor to entity or entities
Getting the entity table
如果你想要获取某个 entity 对应的 SQL 表名,不要直接去通过类名判断,而应该使用 withEntity() 或者 getTable()。 这样的话,即使 entity 到 table 的映射关系发生了变化,你的代码也无需做出更改。
String table = cupboard().withEntity(Book.class).getTable();
// shortcut
String table = cupboard().getTable(Book.class);
频繁操作/Multiple operations
如果你需要对数据库进行多次操作,不想每次都要从 withDatabase() 调用开始,你可以简单的将 DatabaseCompartment 引用保存到一个变量,然后直接使用即可:
java
public void doDatabaseWork(SQLiteDatabase database, Book book) {
DatabaseCompartment dbc = cupboard().withDatabase(database);
dbc.put(book);
dbc.update(Book.class, "title = ?", "android");
}