(翻譯)又一個(gè)Android Sqlite庫: Cupboard

(翻譯)又一個(gè)Android Sqlite庫: Cupboard

Tags: android
原文: https://guides.codepath.com/android/Easier-SQL-with-Cupboard


簡介

Cupboard可以用來在應(yīng)用中管理sqlite.作者是 Hugo Visser. 這里是作者對于Cupboard的一些說明.這是一個(gè)輕量級的易于使用的庫,它專為Android平臺設(shè)計(jì),不像ORMlite那樣臃腫.

使用Android自身提供的SQLiteOpenHelper 也能達(dá)到目的,但是往往要寫很多重復(fù)性的代碼.

與大多數(shù)ORM庫相似,Cupboard將java類與數(shù)據(jù)庫的表映射在一起,同時(shí)java類中的屬性對應(yīng)數(shù)據(jù)庫表的列字段.

開始使用

可以下載jar包: https://search.maven.org/remote_content?g=nl.qbusict&a=cupboard&v=LATEST

也可以使用Maven:

<dependency>
    <groupId>nl.qbusict</groupId>
    <artifactId>cupboard</artifactId>
    <version>(insert latest version)</version>
</dependency>

也可以使用Gradle:

compile 'nl.qbusict:cupboard:(insert latest version)'

配置

需要自定義一個(gè)SQLiteOpenHelper.(在接下來的例子中,將會(huì)使用一個(gè)名為"Bunny"的POJO類,意思是兔子)

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import static nl.qbusict.cupboard.CupboardFactory.cupboard;

public class PracticeDatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "cupboardTest.db";//文件名
    private static final int DATABASE_VERSION = 1;//版本號
    public PracticeDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }
    static {
        // 注冊model
        cupboard().register(Bunny.class);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        // 建表
        cupboard().withDatabase(db).createTables();
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // 升級表
        // Note that existing columns will not be converted
        cupboard().withDatabase(db).upgradeTables();
    }
}

然后可以這樣使用:

PracticeDatabaseHelper dbHelper = 
    new PracticeDatabaseHelper(this);
db = dbHelper.getWritableDatabase();

如何定義Model

定義Model

使用cupboard時(shí),每一個(gè)POJO類都必須包含一個(gè)Long類型的名為"_id"的變量.

public class Bunny {

    public Long _id; // for cupboard
    public String name; // 兔子的名字
    public Integer cuteValue ; // 兔子的可愛程度
    public Bunny() {
        this.name = "noName";
        this.cuteValue = 0;
    }
    public Bunny(String name, Integer cuteValue) {
        this.name = name;
        this.cuteValue = cuteValue;
    }
}

注意:在這些類中,類名將成為創(chuàng)建的數(shù)據(jù)庫表的名字,變量的名字將成為列字段的名字.所以命名時(shí)注意要遵守SQLite里的命名規(guī)范.
然后需要在之前自定義的DatabaseHelper里進(jìn)行注冊.注冊方法是創(chuàng)建一個(gè)static的代碼塊.

static {
      cupboard().register(Bunny.class);
  }

使用注解配置字段名

cupboard支持 @Column()@Ignore() 注解.

@Column()可以指定一個(gè)名字作為要?jiǎng)?chuàng)建的列字段的名字.
@Ignore()可以忽略一個(gè)變量,即不參與創(chuàng)建數(shù)據(jù)庫表.

例如:

public class Bunny {

    public Long _id; // for cupboard
    public String name; // bunny name
    @Column("cute_value")
    public Integer cuteValue; // bunny cuteness
    @Ignore
    public Boolean isAwake;

    ...

增刪改查

創(chuàng)建記錄

// 在數(shù)據(jù)庫中新增一只兔子
Bunny bunny = ...
long id = cupboard().withDatabase(db).put(bunny);

如果bunny對象設(shè)置了"_id"變量的值,那么將會(huì)update指定的行.
如果"_id"變量為null,那么將會(huì)在數(shù)據(jù)庫表中創(chuàng)建新的一行數(shù)據(jù).
兩種情況下,put()函數(shù)都會(huì)返回對應(yīng)的數(shù)據(jù)行的_id的值.

查詢

Bunny bunny = cupboard().withDatabase(db).get(Bunny.class, 12L);

意思是查詢"_id值為12"的Bunny對象.如果結(jié)果不存在,get()將會(huì)返回null.
更復(fù)雜的用法:

//查詢第一個(gè)Bunny對象
Bunny bunny = cupboard().withDatabase(db).query(Bunny.class).get();
// 獲得查詢結(jié)果的Cursor對象
Cursor bunnies = cupboard().withDatabase(db).query(Bunny.class).getCursor();
try {
  // 遍歷產(chǎn)尋結(jié)果
  QueryResultIterable<Bunny> itr = cupboard().withDatabase(db).query(Bunny.class).iterate();
  for (Bunny bunny : itr) {
    // do something with bunny
  }
} finally {
  // 關(guān)閉cursor
  itr.close();
}
// 查詢第一個(gè)名字為Max的Bunny對象
Bunny bunny = cupboard().withDatabase(db).query(Bunny.class).withSelection( "name = ?", "Max").get();

修改記錄

只需先查詢出一條數(shù)據(jù),然后修改一些變量的值,然后使用put方法即可更新數(shù)據(jù):

cupboard().withDatabase(db).put(b);

批量地對查詢結(jié)果進(jìn)行修改:

//假設(shè)需求是將名字為"max"的Bunny的名字改成"Max"
ContentValues values = new ContentValues(1);
values.put("name", "Max")
// 批量地對查詢結(jié)果進(jìn)行修改
cupboard().withDatabase(db).update(Book.class, values, "name = ?", "max");

刪除記錄

// 刪除"_id = 12"的記錄
cupboard().withDatabase(db).delete(Bunny.class, 12L);

// 傳入java對象進(jìn)行刪除
cupboard().withDatabase(db).delete(bunny);
// 傳入查詢條件進(jìn)行刪除,例如刪除所有名字為"Max"的Bunny的記錄
cupboard().withDatabase(db).delete(Bunny.class, "name = ?", "Max");

升級數(shù)據(jù)庫

假設(shè)想要給某個(gè)已經(jīng)存在的model增加一個(gè)屬性,或者想要增加一個(gè)新的model.cupboard提供的數(shù)據(jù)庫升級方案如下:

1.給model增加屬性

public class Bunny {
  public Long _id; // for cupboard
  public String name; // bunny name
  public String furColor; // 新增字段,意思是兔毛的顏色
  public Integer cuteValue ; // bunny cuteness
...

2.修改AndroidManifest.xml中的數(shù)據(jù)庫的version.通常是加1.

public class PracticeDatabaseHelper extends SQLiteOpenHelper {
  private static final String DATABASE_NAME = "cupboardTest.db";
  private static final int DATABASE_VERSION = 2;
  ...

3.在onUpgrade函數(shù)里寫升級邏輯.你必須考慮到所有的可能性.例如從1升級到3,從2升級到3等等.

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      // 這行代碼會(huì)嘗試創(chuàng)建新的列或新的表
      cupboard().withDatabase(db).upgradeTables();

      // 有可能需要給一些新增的列設(shè)置默認(rèn)值
      if (newVersion == 2) {
          ContentValues cv = new ContentValues();
          cv.put("furColor", "black");
          cupboard().withDatabase(db).update(Bunny.class, cv);
      }
}

例子工程

例子見: https://github.com/koalahamlet/cupboardTestApp/tree/master/app/src/main . 包含了一些基本的增刪改查和升級數(shù)據(jù)庫的例子.

常見問題

Cupboard怎么處理重復(fù)ID的情況?例如,數(shù)據(jù)庫里存放的是twitter上的用戶,每個(gè)用戶的id都是唯一的,我想確保數(shù)據(jù)庫里沒有重復(fù)的twitter用戶的id.有沒有辦法指定某一列是主鍵?

你可以啟用@Index和 @CompositeIndex這兩個(gè)注解,方法是:

Cupboard cupboard = new CupboardBuilder().useAnnotations().build();

這兩個(gè)注解的相關(guān)介紹見: https://bitbucket.org/qbusict/cupboard/wiki/existingData

如何定義某一列的數(shù)據(jù)類型(int或text)? Cupboard 會(huì)自動(dòng)判斷所需的數(shù)據(jù)類型嗎?

字段的類型是由model類的屬性的類型自動(dòng)判斷得出的.

如何存儲(chǔ)日期格式的數(shù)據(jù)?

Cupboard中的日期被存儲(chǔ)為Long類型.

long time = Calendar.getInstance().getTimeInMillis();

獲取時(shí)可以按照自己的需求去格式化.(使用SimpleDateFormat,例如"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")

如何表示1對1的關(guān)聯(lián)關(guān)系?

Cupboard不是一個(gè)真正的ORM庫,它不處理關(guān)聯(lián)關(guān)系,否則就會(huì)讓事情變得很復(fù)雜.如果你需要類似級聯(lián)刪除的功能,可以手動(dòng)實(shí)現(xiàn).

如何刪除表中的所有數(shù)據(jù)?

public static void clearAllBunnyData(db) {
    db.execSQL("DELETE FROM " + Bunny.class.getSimpleName());
}

資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末碳胳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子贰盗,更是在濱河造成了極大的恐慌,老刑警劉巖噩凹,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件巴元,死亡現(xiàn)場離奇詭異,居然都是意外死亡驮宴,警方通過查閱死者的電腦和手機(jī)逮刨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堵泽,“玉大人修己,你說我怎么就攤上這事∮蓿” “怎么了睬愤?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長佳谦。 經(jīng)常有香客問我戴涝,道長,這世上最難降的妖魔是什么钻蔑? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任啥刻,我火速辦了婚禮,結(jié)果婚禮上咪笑,老公的妹妹穿的比我還像新娘可帽。我一直安慰自己,他們只是感情好窗怒,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布映跟。 她就那樣靜靜地躺著,像睡著了一般扬虚。 火紅的嫁衣襯著肌膚如雪努隙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天辜昵,我揣著相機(jī)與錄音荸镊,去河邊找鬼。 笑死堪置,一個(gè)胖子當(dāng)著我的面吹牛躬存,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舀锨,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼岭洲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坎匿?” 一聲冷哼從身側(cè)響起盾剩,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤雷激,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后彪腔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侥锦,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年德挣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片快毛。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡格嗅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出唠帝,到底是詐尸還是另有隱情屯掖,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布襟衰,位于F島的核電站贴铜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瀑晒。R本人自食惡果不足惜绍坝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苔悦。 院中可真熱鬧轩褐,春花似錦、人聲如沸玖详。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蟋座。三九已至拗踢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間向臀,已是汗流浹背巢墅。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留飒硅,地道東北人砂缩。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像三娩,于是被迫代替她去往敵國和親庵芭。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容