Android中多表的SQLite數據庫(譯)


原文: Android SQLite Database with Multiple Tables

  在上一篇教程Android SQLite Database Tutorial中,解釋了如何在你的Android應用中使用SQLite數據庫。但它只涵蓋了你的數據庫中只有一個表的情景。有很多人詢問當數據庫中有多個表時如何處理。

  以下解釋了當有多個表存在時如何處理SQLite數據庫。


用例: Todo應用

  為了便於理解,我在這一教程中用了一個真實的用例,一個TODO應用的數據庫方案。本文不會涵蓋如何設計應用的內容,但解釋了數據庫的設計,准備數據庫輔助類和模型。


數據庫設計

  我考慮了一個基本Todo應用,提供最小化的功能,像創建一個todo note賦予它一個tag(s)(類別)。因此我們的數據庫只需要三個表。

  這三個表是:

  todos - 存儲所有的todo notes

  tags - 存儲tags的列表

  todo_tags - 存儲賦給todo的tags

  下圖解釋了表的結構和表之間的關系:


開始一個新項目

  在Eclipse中創建一個新項目:

  1. 在Eclipse中通過File ⇒ New ⇒ Android ⇒ Application Project創建一個新項目。我將包命名為info.androidhive.sqlite並將主活動命名為MainActivity.java

  2. 我們需要額外兩個包存放輔助類和模型類。右鍵src ⇒ New ⇒ Package並將它命名為info.androidhive.sqlite.helperinfo.androidhive.sqlite.model


為表創建模型類

  下一步是為我們的數據庫表創建模型類,將每一單行作為一個對象即可。我們只需要todostags兩個模型。對於todo_tags我們不需要一個模型類。

  3. 在info.androidhive.sqlite.helper中創建一個新的類,代碼如下。這是todos表的模型類。

Todo.java

package info.androidhive.sqlite.model;
 
public class Todo {
 
    int id;
    String note;
    int status;
    String created_at;
 
    // constructors
    public Todo() {
    }
 
    public Todo(String note, int status) {
        this.note = note;
        this.status = status;
    }
 
    public Todo(int id, String note, int status) {
        this.id = id;
        this.note = note;
        this.status = status;
    }
 
    // setters
    public void setId(int id) {
        this.id = id;
    }
 
    public void setNote(String note) {
        this.note = note;
    }
 
    public void setStatus(int status) {
        this.status = status;
    }
     
    public void setCreatedAt(String created_at){
        this.created_at = created_at;
    }
 
    // getters
    public long getId() {
        return this.id;
    }
 
    public String getNote() {
        return this.note;
    }
 
    public int getStatus() {
        return this.status;
    }
}

  4. 在同一個包中為tags表創建另一個模型類,命名為Tags.java。

Tag.java

package info.androidhive.sqlite.model;
 
public class Tag {
 
    int id;
    String tag_name;
 
    // constructors
    public Tag() {
 
    }
 
    public Tag(String tag_name) {
        this.tag_name = tag_name;
    }
 
    public Tag(int id, String tag_name) {
        this.id = id;
        this.tag_name = tag_name;
    }
 
    // setter
    public void setId(int id) {
        this.id = id;
    }
 
    public void setTagName(String tag_name) {
        this.tag_name = tag_name;
    }
 
    // getter
    public int getId() {
        return this.id;
    }
 
    public String getTagName() {
        return this.tag_name;
    }
}

數據庫輔助類

  數據庫輔助類包含所有執行數據庫操作的方法,例如打開連接,關閉連接,插入,更新,讀取,刪除等等。因為這個類是個輔助類,將它放在helper包下。

  5. 在info.androidhive.sqlite.helper創建另一個類,命名為DatabaseHelper.java,繼承自SQLiteOpenHelper

public class DatabaseHelper extends SQLiteOpenHelper {

  6. 添加所需的變量,例如數據庫名稱,數據庫版本號,列名稱。我還在onCreate()方法中執行了建表語句。在DatabaseHelper.java中寫如下代碼:

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {
 
    // Logcat tag
    private static final String LOG = "DatabaseHelper";
 
    // Database Version
    private static final int DATABASE_VERSION = 1;
 
    // Database Name
    private static final String DATABASE_NAME = "contactsManager";
 
    // Table Names
    private static final String TABLE_TODO = "todos";
    private static final String TABLE_TAG = "tags";
    private static final String TABLE_TODO_TAG = "todo_tags";
 
    // Common column names
    private static final String KEY_ID = "id";
    private static final String KEY_CREATED_AT = "created_at";
 
    // NOTES Table - column nmaes
    private static final String KEY_TODO = "todo";
    private static final String KEY_STATUS = "status";
 
    // TAGS Table - column names
    private static final String KEY_TAG_NAME = "tag_name";
 
    // NOTE_TAGS Table - column names
    private static final String KEY_TODO_ID = "todo_id";
    private static final String KEY_TAG_ID = "tag_id";
 
    // Table Create Statements
    // Todo table create statement
    private static final String CREATE_TABLE_TODO = "CREATE TABLE "
            + TABLE_TODO + "(" + KEY_ID + " INTEGER PRIMARY KEY," + KEY_TODO
            + " TEXT," + KEY_STATUS + " INTEGER," + KEY_CREATED_AT
            + " DATETIME" + ")";
 
    // Tag table create statement
    private static final String CREATE_TABLE_TAG = "CREATE TABLE " + TABLE_TAG
            + "(" + KEY_ID + " INTEGER PRIMARY KEY," + KEY_TAG_NAME + " TEXT,"
            + KEY_CREATED_AT + " DATETIME" + ")";
 
    // todo_tag table create statement
    private static final String CREATE_TABLE_TODO_TAG = "CREATE TABLE "
            + TABLE_TODO_TAG + "(" + KEY_ID + " INTEGER PRIMARY KEY,"
            + KEY_TODO_ID + " INTEGER," + KEY_TAG_ID + " INTEGER,"
            + KEY_CREATED_AT + " DATETIME" + ")";
 
    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
 
    @Override
    public void onCreate(SQLiteDatabase db) {
 
        // creating required tables
        db.execSQL(CREATE_TABLE_TODO);
        db.execSQL(CREATE_TABLE_TAG);
        db.execSQL(CREATE_TABLE_TODO_TAG);
    }
 
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // on upgrade drop older tables
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_TODO);
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_TAG);
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_TODO_TAG);
 
        // create new tables
        onCreate(db);
    }

CRUD (Create, Read, Update and Delete) 操作

  現在起我們將一個方法一個方法地完善DatabaseHelper.class


1. 創建一個Todo

  這個方法將會在todos表中創建一個todo條目。在同一個方法中,我們還會賦予todo一個tag名稱,這會在todo_tags表中插入一行。

/*
 * Creating a todo
 */
public long createToDo(Todo todo, long[] tag_ids) {
    SQLiteDatabase db = this.getWritableDatabase();
 
    ContentValues values = new ContentValues();
    values.put(KEY_TODO, todo.getNote());
    values.put(KEY_STATUS, todo.getStatus());
    values.put(KEY_CREATED_AT, getDateTime());
 
    // insert row
    long todo_id = db.insert(TABLE_TODO, null, values);
 
    // assigning tags to todo
    for (long tag_id : tag_ids) {
        createTodoTag(todo_id, tag_id);
    }
 
    return todo_id;
}

2. 獲取一個Todo

  以下將會從todos表中獲取一個todo對象。

SELECT * FROM todos WHERE id = 1;

/*
 * get single todo
 */
public Todo getTodo(long todo_id) {
    SQLiteDatabase db = this.getReadableDatabase();
 
    String selectQuery = "SELECT  * FROM " + TABLE_TODO + " WHERE "
            + KEY_ID + " = " + todo_id;
 
    Log.e(LOG, selectQuery);
 
    Cursor c = db.rawQuery(selectQuery, null);
 
    if (c != null)
        c.moveToFirst();
 
    Todo td = new Todo();
    td.setId(c.getInt(c.getColumnIndex(KEY_ID)));
    td.setNote((c.getString(c.getColumnIndex(KEY_TODO))));
    td.setCreatedAt(c.getString(c.getColumnIndex(KEY_CREATED_AT)));
 
    return td;
}

3. 獲取所有Todo對象

  獲取所有的todo對象包含讀取所有的todo行,並添加到一個列表中。

SELECT * FROM todos;

/*
 * getting all todos
 * */
public List<Todo> getAllToDos() {
    List<Todo> todos = new ArrayList<Todo>();
    String selectQuery = "SELECT  * FROM " + TABLE_TODO;
 
    Log.e(LOG, selectQuery);
 
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor c = db.rawQuery(selectQuery, null);
 
    // looping through all rows and adding to list
    if (c.moveToFirst()) {
        do {
            Todo td = new Todo();
            td.setId(c.getInt((c.getColumnIndex(KEY_ID))));
            td.setNote((c.getString(c.getColumnIndex(KEY_TODO))));
            td.setCreatedAt(c.getString(c.getColumnIndex(KEY_CREATED_AT)));
 
            // adding to todo list
            todos.add(td);
        } while (c.moveToNext());
    }
 
    return todos;
}

4. 獲取一個Tag標簽下的所有Todo對象

  這和讀取所有行相同,但要按照Tag標簽過濾todo對象。查看下面的查詢語句,它按照tag標簽的監視列表來獲取todo對象。

SELECT * FROM todos td, tags tg, todo_tags tt WHERE tg.tag_name = ‘Watchlist’ AND tg.id = tt.tag_id AND td.id = tt.todo_id;

/*
 * getting all todos under single tag
 * */
public List<Todo> getAllToDosByTag(String tag_name) {
    List<Todo> todos = new ArrayList<Todo>();
 
    String selectQuery = "SELECT  * FROM " + TABLE_TODO + " td, "
            + TABLE_TAG + " tg, " + TABLE_TODO_TAG + " tt WHERE tg."
            + KEY_TAG_NAME + " = '" + tag_name + "'" + " AND tg." + KEY_ID
            + " = " + "tt." + KEY_TAG_ID + " AND td." + KEY_ID + " = "
            + "tt." + KEY_TODO_ID;
 
    Log.e(LOG, selectQuery);
 
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor c = db.rawQuery(selectQuery, null);
 
    // looping through all rows and adding to list
    if (c.moveToFirst()) {
        do {
            Todo td = new Todo();
            td.setId(c.getInt((c.getColumnIndex(KEY_ID))));
            td.setNote((c.getString(c.getColumnIndex(KEY_TODO))));
            td.setCreatedAt(c.getString(c.getColumnIndex(KEY_CREATED_AT)));
 
            // adding to todo list
            todos.add(td);
        } while (c.moveToNext());
    }
 
    return todos;
}

5. 更新一個Todo

  下面的方法將會更新一個todo。它只會更新todo的值,不包括tag標簽。

/*
 * Updating a todo
 */
public int updateToDo(Todo todo) {
    SQLiteDatabase db = this.getWritableDatabase();
 
    ContentValues values = new ContentValues();
    values.put(KEY_TODO, todo.getNote());
    values.put(KEY_STATUS, todo.getStatus());
 
    // updating row
    return db.update(TABLE_TODO, values, KEY_ID + " = ?",
            new String[] { String.valueOf(todo.getId()) });
}

6. 刪除一個Todo

  將todo的id傳給下面的方法,從數據庫中刪除一項todo。

/*
 * Deleting a todo
 */
public void deleteToDo(long tado_id) {
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_TODO, KEY_ID + " = ?",
            new String[] { String.valueOf(tado_id) });
}

  到目前為止我們已經給todos表創建了CRUD方法。現在我們開始給tags表創建所需的方法。

7. 創建一個Tag

  下面的方法將會給tags表插入一行。

/*
 * Creating tag
 */
public long createTag(Tag tag) {
    SQLiteDatabase db = this.getWritableDatabase();
 
    ContentValues values = new ContentValues();
    values.put(KEY_TAG_NAME, tag.getTagName());
    values.put(KEY_CREATED_AT, getDateTime());
 
    // insert row
    long tag_id = db.insert(TABLE_TAG, null, values);
 
    return tag_id;
}

8. 獲取所有的Tag標簽

  在tags表中執行查詢所有的語句將會給你一個tag標簽的列表。

SELECT * FROM tags;

/**
 * getting all tags
 * */
public List<Tag> getAllTags() {
    List<Tag> tags = new ArrayList<Tag>();
    String selectQuery = "SELECT  * FROM " + TABLE_TAG;
 
    Log.e(LOG, selectQuery);
 
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor c = db.rawQuery(selectQuery, null);
 
    // looping through all rows and adding to list
    if (c.moveToFirst()) {
        do {
            Tag t = new Tag();
            t.setId(c.getInt((c.getColumnIndex(KEY_ID))));
            t.setTagName(c.getString(c.getColumnIndex(KEY_TAG_NAME)));
 
            // adding to tags list
            tags.add(t);
        } while (c.moveToNext());
    }
    return tags;
}

9. 更新Tags

  下面的方法將會更新tag。

/*
 * Updating a tag
 */
public int updateTag(Tag tag) {
    SQLiteDatabase db = this.getWritableDatabase();
 
    ContentValues values = new ContentValues();
    values.put(KEY_TAG_NAME, tag.getTagName());
 
    // updating row
    return db.update(TABLE_TAG, values, KEY_ID + " = ?",
            new String[] { String.valueOf(tag.getId()) });
}

10. 刪除一個Tag標簽下的所有Tag和Todo對象。

  下面的方法將會從數據庫中刪除一個tag。它也會刪除該tag標簽下的所有todo對象,但這一行為是可選的。

should_delete_all_tag_todos = 傳遞true代表將會刪除tag標簽下的所有todo對象。

/*
 * Deleting a tag
 */
public void deleteTag(Tag tag, boolean should_delete_all_tag_todos) {
    SQLiteDatabase db = this.getWritableDatabase();
 
    // before deleting tag
    // check if todos under this tag should also be deleted
    if (should_delete_all_tag_todos) {
        // get all todos under this tag
        List<Todo> allTagToDos = getAllToDosByTag(tag.getTagName());
 
        // delete all todos
        for (Todo todo : allTagToDos) {
            // delete todo
            deleteToDo(todo.getId());
        }
    }
 
    // now delete the tag
    db.delete(TABLE_TAG, KEY_ID + " = ?",
            new String[] { String.valueOf(tag.getId()) });
}

  下面是訪問todo_tags表中數據的方法。

11. 給Todo對象分配一個Tag

  下面的方法將會給一個todo對象賦予一個tag標簽。你也可以通過調用這個函數多次將多個tag賦予同一個todo對象。

/*
 * Creating todo_tag
 */
public long createTodoTag(long todo_id, long tag_id) {
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    values.put(KEY_TODO_ID, todo_id);
    values.put(KEY_TAG_ID, tag_id);
    values.put(KEY_CREATED_AT, getDateTime());

    long id = db.insert(TABLE_TODO_TAG, null, values);

    return id;
}

12. 移除Todo的Tag

  下面的方法將會移除賦予給一個todo的tag。

/**
 * Deleting a todo tag
 */
public void deleteToDoTag(long id) {
    SQLiteDatabase db = this.getWritableDatabase();
    db.delete(TABLE_TODO, KEY_ID + " = ?",
            new String[] { String.valueOf(id) });
}

13. 改變todo的tag

  下面的方法簡單地替換了一個todo的tag標簽。

/*
 * Updating a todo tag
 */
public int updateNoteTag(long id, long tag_id) {
    SQLiteDatabase db = this.getWritableDatabase();
 
    ContentValues values = new ContentValues();
    values.put(KEY_TAG_ID, tag_id);
 
    // updating row
    return db.update(TABLE_TODO, values, KEY_ID + " = ?",
            new String[] { String.valueOf(id) });
}

14. 關閉數據庫連接

  重要的一點一旦你使用完了數據庫,不要忘了關閉數據庫連接。當你無需再訪問數據庫時,調用下面的方法。

//closing database
public void closeDB() {
    SQLiteDatabase db = this.getReadableDatabase();
    if (db != null && db.isOpen())
        db.close();
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM