Android數據庫ORM框架:GreenDAO使用簡介

Android最常用的數據庫是SQLite,通常使用SQLite進行CRUD操作需要記住一些常用的SQL語句,這不利于提高開發效率,而且很容易出錯。ORM(Object-Relational Mapping)框架的引入使得對數據庫的操作也能利用OOP(Object-oriented programming)思想實現。ORM通過將數據庫中的一張張表映射成Java的對象,并提供統一的API提供CRUD操作,使得操作數據庫變得簡單,開發者可以將精力放在處理重要的邏輯,而不是記住SQL語句上。

對象關系映射(ORM)

有幾個常用的ORM開源框架,它們的特點比較如下:

Android ORM框架比較

其中由GreenRobot公司開源的GreenDAO尤為出色,該開源庫體積小,而且由于完全沒有使用反射,所以速度很快,本文將介紹GreenDAO的使用。

特點

1. 魯棒性強, 2011年開始使用
2. 很小, <100k
3. 速度快
4. 安全易用的API
5. 強大的join語句
6. 靈活的屬性類型

使用步驟

1. 建立一個java工程,給每張表定義一個對應的Entity,運行工程,生成一系列的輸出文件
2. 將這些輸出文件拷貝到Android工程里,并在gradle里做相應的配置
3. 可以在Android里通過OOP的方式訪問數據庫了

首先打開Eclipse,建立一個java工程,引入兩個庫文件freemarker.jar和greendao-generator-1.3.1.jar,可以開始定義Entity了。

在greenDAO里,一個Entity對應SQLite的一張表,可以給Entity設置Property,Relation和Index,分別代表數據表的屬性,關系和索引(一對一,一對多)。

Entity

這里的Schema類包含了數據庫層面的信息,如數據庫版本和名稱:

Schema schema = new Schema(1, "me.chunyu.support");

利用Schema,可以給每張表建立一個對應的Entity。Entity包含了Property,Relation和Index。

Property

對Property的設置如下:

public static void addGroupChatRecord(Schema schema) {        
    Entity groupChatRecord = schema.addEntity("GroupChatRecord");     
    groupChatRecord.addStringProperty("messageMD5ID").primaryKey(); // conversation id + message id md5值        
    groupChatRecord.addBooleanProperty("hasRead"); // 是否已讀        
    groupChatRecord.addDateProperty("messageTime");        
}

這個Entity命名為GroupChatRecord,記錄的是好友群的數據,通過addStringProperty,addBooleanProperty,addDateProperty分別添加類型為String,Boolean和Date的屬性,對應數據表里相應的字段,并通過primaryKey()指定messageMD5ID為主鍵。

Relation

addToOne定義一對一的關系:

Property avatarIdProperty = user.addLongProperty("avatarId").getProperty();
user.addToOne(picture, avatarIdProperty);

上面的代碼中,user和picture都是Entity,通過addToOne指定user的頭像屬性對應picture表里的一條記錄。

addToMany定義一對多的關系:

Property customerId = order.addLongProperty("customerId").notNull().getProperty();
ToMany customerToOrders = customer.addToMany(order, customerId);

上面的代碼中,通過addToMany指定一個用戶(customer)可以對應多個訂單(order)。這樣,通過customer.getOrders()就可以獲取一個用戶的所有訂單:

List orders = customer.getOrders();
Index

通過給數據表建立索引可以提高檢索效率,Index代表數據表的索引,通過addProperty添加索引字段,可以建立獨立索引或聯合索引。Entity通過addIndex方法添加索引:

Index index = new Index();
index.addProperty(property1);
index.addProperty(property2);
entity.addIndex(index);

定義完Entity后,調用DAOGenerator類的generateAll方法生成DAO文件,參數分布是代表數據庫的schema和文件輸出路徑:

// 生成DAO文件到指定路徑
new DaoGenerator().generateAll(schema, "../");

生成的公共文件,包括DaoMaster.java/DaoSession.java,另外每個Entity對應生成兩個文件EntityName.java/EntityNameDao.java,文件內容如下:
1. EntityName.java: Entity的各個屬性,及get/set方法
2. EntityNameDao.java:Entity的CRUD方法
3. DaoSession.java:提供獲取各個EntityNameDao的方法
4. DaoMaster.java:生成DaoSession;進行數據庫生成,升級

使用:
首先初始化DaoMaster,然后通過DaoMaster獲得DaoSession,樣例代碼:

public class GreenDaoUtils {    
    private static DaoSession daoSession;    
    private static byte[] _lock = {};    

    /**獲取Dao Session**/    
    public static DaoSession getDaoSession(Context context, String dbName) {        
        if (daoSession != null) {            
            return daoSession;        
        }        

        synchronized (_lock) {            
            if (daoSession != null) {                
                return daoSession;            
            }           
            SQLiteDatabase db;            
            DaoMaster daoMaster;            
            
            DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, dbName, null);
            db = helper.getWritableDatabase();        
            daoMaster = new DaoMaster(db);        
            daoSession = daoMaster.newSession();      
  
            return daoSession;    
        }
    }
}

代碼中getWritableDatabase用于新建或返回數據庫,如果第一次執行該代碼,新建數據庫,以后執行返回已建好的數據庫。同時,如果數據庫版本升級了,會執行helper的onUpgrade函數,執行升級數據庫的操作。

樣例代碼中helper類型是DaoMaster.DevOpenHelper,該類的onUpgrade函數會刪除所有表,再新建所有表,只適用于開發階段。開發者需要實現自己的OpenHelper,重寫onUpgrade函數,指明如何進行數據庫的升級。下面是DaoMaster.DevOpenHelper的實現:

public static class DevOpenHelper extends OpenHelper {    
    public DevOpenHelper(Context context, String name, CursorFactory factory) {        
        super(context, name, factory);    
    }    

    @Override    
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {        
        Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");        
        dropAllTables(db, true);        
        onCreate(db);    
    }
}
使用DAO API進行CRUD操作:

Create:

entityNameDao.insert(newEntity)

Read:

List joes = userDao.queryBuilder()

                    .where(Properties.FirstName.eq("Joe"))

                    .orderAsc(Properties.LastName)

                    .list();

QueryBuilder qb = userDao.queryBuilder();

qb.where(Properties.FirstName.eq("Joe"),

    qb.or(Properties.YearOfBirth.gt(1970),

        qb.and(Properties.YearOfBirth.eq(1970), 
            Properties.MonthOfBirth.ge(10))));

List youngJoes = qb.list();

Update:

entityNameDao.update(newEntity);

Delete:

entityNameDao.deleteByKey(id)
// OR
entityNameDao.delete(note);
執行raw sql語句

除了使用greenDao提供的接口進行增刪改查操作,greenDao還提供了執行Sql語句的功能,示例如下:

Query query = userDao.queryBuilder()
    .where(new StringCondition(“_ID IN ” +“(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)”)
    .build();


Query query = userDao
    .queryRawCreate(  ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");

同時,如果感覺沒有得到期望的結果,可以通過下面代碼打開greenDao調試功能,輸出生成的sql語句進行debug:

QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;

參考:
https://github.com/greenrobot/greenDAO
http://greenrobot.org/greendao/documentation/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容