昨天我們簡單說明了如何利用 SQLiteOpenHelper 幫我們建立/管理資料庫,今天會繼續介紹 SQLiteDatabase 這個類別 [1],它可以幫助我們新增/刪除/更新/搜尋資料庫內的資料。筆者在昨天所建立的 lincyu.babylog.db 這個 package 下另外新增了兩個檔案:Baby.java 和 BabyDB.java。
Baby.java 的內容相當單純,其實就是建立一個寶寶類別,讓我們可以產生寶寶物件:
package lincyu.babylog.db;
public class Baby {
public static final int GENDER_UNKNOWN = 0;
public static final int GENDER_MALE = 1;
public static final int GENDER_FEMALE = 2;
public int babyid;
public String name;
public String nickname;
public String headshot;
public long birthday;
public int gender;
Baby(int babyid, String name, String nickname, String headshot,
long birthday, int gender) {
this.babyid = babyid;
this.name = name;
this.nickname = nickname;
this.headshot = headshot;
this.birthday = birthday;
this.gender = gender;
}
public Baby() {
babyid = -1;
name = "";
nickname = "";
headshot = "";
birthday = 0;
gender = GENDER_UNKNOWN;
}
@Override
public String toString() {
int namelength = name.length();
int nicknamelength = nickname.length();
if (namelength == 0 && nicknamelength == 0) {
return "";
} else if (namelength == 0 && nicknamelength != 0) {
return nickname;
} else if (namelength != 0 && nicknamelength == 0) {
return name;
}
return nickname + " (" + name + ")";
}
}
相信這個檔案應該不需要筆者說明了。我們現在來討論 BabyDB.java,其內容如下所示:
package lincyu.babylog.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
public class BabyDB {
private static final String BABYID = "_babyid";
private static final String NAME = "_name";
private static final String NICKNAME = "_nickname";
private static final String BIRTHDAY = "_birthday";
private static final String GENDER = "_gender";
private static final String HEADSHOT = "_headshot";
static final String BABY_TABLE = "babytable";
static final String CREATE_BABY_TABLE = "create table " +
BABY_TABLE + "(" +
BABYID + " INTEGER PRIMARY KEY " +
"AUTOINCREMENT DEFAULT 1 , " +
NAME + ", " +
NICKNAME + ", " +
BIRTHDAY + ", " +
GENDER + ", " +
HEADSHOT + ");";
public synchronized static void addBaby(Context context, Baby baby) {
addBaby(context, baby.babyid, baby.name, baby.nickname, baby.headshot,
baby.birthday, baby.gender);
}
public synchronized static void addBaby(Context context, int babyid,
String name, String nickname, String headshot,
long birthday, int gender) {
DBOpenHelper dbHelper = new DBOpenHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues cv = new ContentValues();
cv.put(NAME, name);
cv.put(NICKNAME, nickname);
cv.put(HEADSHOT, headshot);
cv.put(BIRTHDAY, birthday);
cv.put(GENDER, gender);
if (babyid == -1) { // New Record
db.insert(BABY_TABLE, null, cv);
} else { // Existing Record
db.update(BABY_TABLE, cv, BABYID + "=" + babyid, null);
}
db.close();
}
public synchronized static void removeBaby(Context context, int babyid) {
DBOpenHelper dbHelper = new DBOpenHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete(BABY_TABLE, BABYID + "=" + babyid, null);
db.close();
}
public synchronized static ArrayList<Baby> getAllBabies(Context context) {
ArrayList<Baby> babylist = new ArrayList<Baby>();
DBOpenHelper dbHelper = new DBOpenHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
// Cursor c = db.rawQuery("select * from " + BABY_TABLE + ";", null);
Cursor c = db.query(BABY_TABLE, null, null, null, null, null, null);
getRecordsKernel(c, babylist);
c.close();
db.close();
return babylist;
}
public synchronized static Baby getBabyById(Context context, int babyid) {
DBOpenHelper dbHelper = new DBOpenHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor c = db.query(BABY_TABLE, null, BABYID + "=" + babyid, null, null, null, null);
Baby baby = new Baby();
if (c.getCount() == 1) {
c.moveToFirst();
baby = db2record(c);
}
c.close();
db.close();
return baby;
}
private static void getRecordsKernel(Cursor c, ArrayList<Baby> babylist) {
c.moveToFirst();
for (int i = 0; i < c.getCount(); i++) {
Baby baby = db2record(c);
babylist.add(baby);
c.moveToNext();
}
}
private static Baby db2record(Cursor c) {
int babyid = -1;
try {
babyid = c.getInt(c.getColumnIndex(BABYID));
} catch (Exception e) {
babyid = -1;
}
String name = null;
try {
name = c.getString(c.getColumnIndex(NAME));
} catch (Exception e) {
name = "";
}
String nickname = null;
try {
nickname = c.getString(c.getColumnIndex(NICKNAME));
} catch (Exception e) {
nickname = "";
}
String headshot = null;
try {
headshot = c.getString(c.getColumnIndex(HEADSHOT));
} catch (Exception e) {
headshot = "";
}
long birthday = 0;
try {
birthday = c.getLong(c.getColumnIndex(BIRTHDAY));
} catch (Exception e) {
birthday = 0;
}
int gender = 0;
try {
gender = c.getInt(c.getColumnIndex(GENDER));
} catch (Exception e) {
gender = Baby.GENDER_UNKNOWN;
}
Baby baby = new Baby(babyid, name, nickname, headshot,
birthday, gender);
return baby;
}
}
首先程式定義了一個字串常數 CREATE_BABY_TABLE,熟悉 SQL 語法的讀者可能已經看出常數值是一個 SQL 語法,目的是建立一個新表格 (Table),讀者是否還記得昨天介紹的 DBOpenHelper.java,onCreate 方法內有這麼一行:
db.execSQL(BabyDB.CREATE_BABY_TABLE);
其中 db 是 SQLiteDatabase 物件,也就是今天的重點,SQLiteDatabase 類別的 execSQL 方法可讓我們執行 Non-query SQL 敘述,如 insert, update, delete, alter table, create table, drop table 等,例如昨天筆者有提到我們可能會在 onUpgrade 裡加上如下的敘述:「db.execSQL("alter table " + BabyDB.BABY_TABLE + " add column " + BabyDB.MOTHERNAME + ";");」,然而對於 insert, update, delete 這 3 個 SQL 敘述,SQLiteDatabase 另外提供了 insert, update, delete 等 Methods,BabyDB.java 就是直接使用這些 Methods。
BabyDB.java 的 addBaby 這個方法示範了insert 和 update 的用法,首先 ,我們產生一個 DBOpenHelper 物件,DBOpenHelper 昨天已經介紹過了,會幫我們檢查資料庫是否存在、是否需要更新,接著呼叫 SQLiteOpenHelper 類別的 getWritableDatabase 方法取得一個 SQLiteDatabase 物件,有了這個 SQLiteDatabase 物件,我們就可以執行相關的 SQL 敘述。
程式是利用 ContentValues [2] 來準備 insert/update 的資料,資料是採用 Key-Value 的方式放入,其中 Key 是表格的欄位名稱 (Column name),Value 則是要 insert/update 的值,這裡有一點要提醒讀者,由於 _babyid 這個欄位是 PRIMARY KEY 且設定成會自動加一,因此我們不需要手動設定其值。
接著,筆者設定成若呼叫 addBaby 時 babyid 的值為 -1 代表要插入一筆新記錄,因此呼叫 SQLiteDatabase 物件的 insert,insert 需要 3 個參數,第 1 個參數是表格 (Table)名稱,第 2 個參數是處理 ContentValues 為空的情況 (詳細說明請參考 [1]),此處填上 null 即可,第 3 個參數則是代入前面產生的 ContentValues 物件。若呼叫 addBaby 時 babyid 的值不是 -1 代表要更新一筆已經存在的記錄 (Record),update 的第 1 個參數是表格名稱,第 2 個參數 ContentValues 物件,第 3 和第 4 個參數是跟 SQL 的 where 敘述相關,第 4 個參數是在第 3 個參數有包含「?」的情況下才會使用到,下面是一個範例:
String[] args = { "Bill", “bill@fake.mail.com” };
db.update(“TABLE_NAME", cv, "name=? and email=?", args);
在我們自己的程式碼中,由於第 3 個參數直接將 babyid 代入,沒有用問號,因此第 4 個參數填上 null 即可。而第 3 個參數所代表的意義是我們要更新的記錄是 _babyid 值為 babyid 的那一筆記錄。最後程式呼叫 close 將資料庫關起來,至此就完成了 insert 和 update 的說明。
接著我們來看 removeBaby 這個 Method,delete 的第 2 和第 3 個參數就是跟 update 的第 3 和第 4 個參數一樣,分別是 whereClause 和 whereArgs,而 removeBaby 內的寫法代表我們要刪除某個特定 babyid 的記錄,其餘的敘述就應該不需贅述了。
今天我們集中在 Non-query SQL 敘述的介紹,SQLiteDatabase 物件的 execSQL 方法可執行 Non-query SQL 敘述,SQLiteDatabase 還特別針對 insert/update/delete 提供了特定的 Methods。明天我們會介紹 SQLiteDatabase 針對跟查詢 (Query) 相關的 SQL 敘述所提供的 Methods。
參考資料
[1] SQLiteDatabase | Android Developers, http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
[2] ContentValues | Android Developers, http://developer.android.com/reference/android/content/ContentValues.html