上一篇文章,我们有讲解到GreenDao的基本应用,本文开始深了解GreenDao的源码。当我们编写好了Entity类之后,会自动生成DaoMaster、DaoSession、Entity Dao这三个核心类。
三者之间的关系如下:
//生成数据库文件,名为students-db
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "xxx.db", null);
SQLiteDatabase db = helper.getWritableDatabase();
//建立特定模式下的所有的DAO对象和数据库db对象的映射
DaoMaster master = new DaoMaster(db);
//管理特定模式下的所有DAO对象,并提供一些通用的CRUD持久化方法
DaoSession session = master.newSession();
//得到指定的StudentDao对象
StudentDao dao = session.getStudentDao();
dao.insert(entity);
//...
1. DaoMaster
public class DaoMaster extends AbstractDaoMaster {
public static final int SCHEMA_VERSION = 1;
// 创建数据库
public static void createAllTables(Database db, boolean ifNotExists) {
UserDao.createTable(db, ifNotExists);
}
// 删除数据库
public static void dropAllTables(Database db, boolean ifExists) {
UserDao.dropTable(db, ifExists);
}
// 获取DaoSession对象
public static DaoSession newDevSession(Context context, String name) {
Database db = new DevOpenHelper(context, name).getWritableDb();
DaoMaster daoMaster = new DaoMaster(db);
return daoMaster.newSession();
}
public DaoMaster(SQLiteDatabase db) {
this(new StandardDatabase(db));
}
public DaoMaster(Database db) {
super(db, SCHEMA_VERSION);
//注意此处传入UserDao对象
registerDaoClass(UserDao.class);
}
public DaoSession newSession() {
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
}
public DaoSession newSession(IdentityScopeType type) {
return new DaoSession(db, type, daoConfigMap);
}
public static abstract class OpenHelper extends DatabaseOpenHelper {
public OpenHelper(Context context, String name) {
super(context, name, SCHEMA_VERSION);
}
public OpenHelper(Context context, String name, CursorFactory factory)
{
super(context, name, factory, SCHEMA_VERSION);
}
@Override
public void onCreate(Database db) {
Log.i("greenDAO", "Creating tables for schema version " +
SCHEMA_VERSION);
createAllTables(db, false);
}
}
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name) {
super(context, name);
}
public DevOpenHelper(Context context, String name,
CursorFactory factory)
{
super(context, name, factory);
}
//数据库升级,会删除所有的表格,然后再创建数据库
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " +
oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}
}
}
DaoMaster类里面有两个静态内部类OpenHelper继承了DatabaseOpenHelper类,而DatabaseOpenHelper类又继承了SQLiteOpenHelper类。DevOpenHelper类则继承了OpenHelper。DevOpenHelper类的构造函数里面参数name代表类数据库名称。onCreate函数会调用createAllTables函数,onUpgrade函数会调用dropAllTables,再重新创建数据库。
AbstractDaoMaster.java
public abstract class AbstractDaoMaster {
protected final SQLiteDatabase db;
protected final int schemaVersion;
// EntityDao类为Key
protected final Map>, DaoConfig> daoConfigMap;
public AbstractDaoMaster(SQLiteDatabase db, int schemaVersion) {
this.db = db;
this.schemaVersion = schemaVersion;
daoConfigMap = new HashMap>, DaoConfig>();
}
// 初始化daoConfigMap对象
protected void registerDaoClass(Class extends AbstractDao, ?>> daoClass) {
DaoConfig daoConfig = new DaoConfig(db, daoClass);
daoConfigMap.put(daoClass, daoConfig);
}
public int getSchemaVersion() {
return schemaVersion;
}
/** Gets the SQLiteDatabase for custom database access.
** Not needed for greenDAO entities.
*/
public SQLiteDatabase getDatabase() {
return db;
}
public abstract AbstractDaoSession newSession();
public abstract AbstractDaoSession newSession(IdentityScopeType type);
}
daoConfigMap其实是存储了EntityDao与db数据库之前的映射关系。
2. DaoSession
public class DaoSession extends AbstractDaoSession {
private final DaoConfig studentDaoConfig;
private final StudentDao studentDao;
public DaoSession(SQLiteDatabase db, IdentityScopeType type,
Map>, DaoConfig>
daoConfigMap) {
super(db);
studentDaoConfig = daoConfigMap.get(StudentDao.class).clone();
studentDaoConfig.initIdentityScope(type);
studentDao = new StudentDao(studentDaoConfig, this);
registerDao(Student.class, studentDao);
}
public void clear() {
studentDaoConfig.getIdentityScope().clear();
}
public StudentDao getStudentDao() {
return studentDao;
}
}
AbstractDaoSession.java
public class AbstractDaoSession {
private final SQLiteDatabase db;
private final Map, AbstractDao, ?>> entityToDao;
public AbstractDaoSession(SQLiteDatabase db) {
this.db = db;
this.entityToDao = new HashMap, AbstractDao, ?>>();
}
protected void registerDao(Class entityClass, AbstractDao dao) {
entityToDao.put(entityClass, dao);
}
/** Convenient call for {@link AbstractDao#insert(Object)}. */
public long insert(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
return dao.insert(entity);
}
/** Convenient call for {@link AbstractDao#insertOrReplace(Object)}. */
public long insertOrReplace(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
return dao.insertOrReplace(entity);
}
/** Convenient call for {@link AbstractDao#refresh(Object)}. */
public void refresh(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
dao.refresh(entity);
}
/** Convenient call for {@link AbstractDao#update(Object)}. */
public void update(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
dao.update(entity);
}
//...
/** Convenient call for {@link AbstractDao#delete(Object)}. */
public void delete(T entity) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entity.getClass());
dao.delete(entity);
}
/** Convenient call for {@link AbstractDao#deleteAll()}. */
public void deleteAll(Class entityClass) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
dao.deleteAll();
}
/** Convenient call for {@link AbstractDao#load(Object)}. */
public T load(Class entityClass, K key) {
@SuppressWarnings("unchecked")
AbstractDao dao = (AbstractDao) getDao(entityClass);
return dao.load(key);
}
/** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */
public SQLiteDatabase getDatabase() {
return db;
}
/**
* Creates a new {@link AsyncSession} to issue asynchronous entity operations. See {@link AsyncSession} for details.
*/
public AsyncSession startAsyncSession() {
return new AsyncSession(this);
}
}
3. Dao
public class StudentDao extends AbstractDao {
public static final String TABLENAME = "STUDENT";
/**
* Properties of entity Student.
* Can be used for QueryBuilder and for referencing column names.
*/
public static class Properties {
public final static Property Id = new Property(0, Long.class, "id", true, "_id");
public final static Property Name = new Property(1, String.class, "name", false, "NAME");
public final static Property Age = new Property(2, Integer.class, "age", false, "AGE");
public final static Property Is_man = new Property(3, Boolean.class, "is_man", false, "IS_MAN");
};
public StudentDao(DaoConfig config) {
super(config);
}
public StudentDao(DaoConfig config, DaoSession daoSession) {
super(config, daoSession);
}
/** Creates the underlying database table. */
public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
String constraint = ifNotExists? "IF NOT EXISTS ": "";
db.execSQL("CREATE TABLE " + constraint + "\"STUDENT\" (" + //
"\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
"\"NAME\" TEXT NOT NULL ," + // 1: name
"\"AGE\" INTEGER," + // 2: age
"\"IS_MAN\" INTEGER);"); // 3: is_man
}
/** Drops the underlying database table. */
public static void dropTable(SQLiteDatabase db, boolean ifExists) {
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"STUDENT\"";
db.execSQL(sql);
}
/** @inheritdoc */
@Override
protected void bindValues(SQLiteStatement stmt, Student entity) {
stmt.clearBindings();
Long id = entity.getId();
if (id != null) {
stmt.bindLong(1, id);
}
stmt.bindString(2, entity.getName());
Integer age = entity.getAge();
if (age != null) {
stmt.bindLong(3, age);
}
Boolean is_man = entity.getIs_man();
if (is_man != null) {
stmt.bindLong(4, is_man ? 1L: 0L);
}
}
/** @inheritdoc */
@Override
public Long readKey(Cursor cursor, int offset) {
return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
}
/** @inheritdoc */
@Override
public Student readEntity(Cursor cursor, int offset) {
Student entity = new Student( //
cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
cursor.getString(offset + 1), // name
cursor.isNull(offset + 2) ? null : cursor.getInt(offset + 2), // age
cursor.isNull(offset + 3) ? null : cursor.getShort(offset + 3) != 0 // is_man
);
return entity;
}
/** @inheritdoc */
@Override
public void readEntity(Cursor cursor, Student entity, int offset) {
entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
entity.setName(cursor.getString(offset + 1));
entity.setAge(cursor.isNull(offset + 2) ? null : cursor.getInt(offset + 2));
entity.setIs_man(cursor.isNull(offset + 3) ? null : cursor.getShort(offset + 3) != 0);
}
/** @inheritdoc */
@Override
protected Long updateKeyAfterInsert(Student entity, long rowId) {
entity.setId(rowId);
return rowId;
}
/** @inheritdoc */
@Override
public Long getKey(Student entity) {
if(entity != null) {
return entity.getId();
} else {
return null;
}
}
/** @inheritdoc */
@Override
protected boolean isEntityUpdateable() {
return true;
}
}
其中bindValues()这个方法就是绑定实体的属性名和表中的字段名的,还有比较重要的就是这个静态内部类Properties,该类中分别对每一个实体类的属性都创建了一个Property对象,而我们可以根据Property来得到这个属性对应表中的列名、是否为主键等值,其中还包括了一些方法,比如判断表中某个字段的值是否和value相等:eq(Object value);
Property源码如下:
public class Property {
public final int ordinal;
public final Class> type;
public final String name;
public final boolean primaryKey;
public final String columnName;
public Property(int ordinal, Class> type, String name,
boolean primaryKey, String columnName) {
this.ordinal = ordinal;
this.type = type;
this.name = name;
this.primaryKey = primaryKey;
this.columnName = columnName;
}
/** Creates an "equal ('=')" condition for this property. */
public WhereCondition eq(Object value) {
return new PropertyCondition(this, "=?", value);
}
/** Creates an "not equal ('<>')" condition for this property. */
public WhereCondition notEq(Object value) {
return new PropertyCondition(this, "<>?", value);
}
/** Creates an "LIKE" condition for this property. */
public WhereCondition like(String value) {
return new PropertyCondition(this, " LIKE ?", value);
}
/** Creates an "BETWEEN ... AND ..." condition for this property. */
public WhereCondition between(Object value1, Object value2) {
Object[] values = { value1, value2 };
return new PropertyCondition(this, " BETWEEN ? AND ?", values);
}
/** Creates an "IN (..., ..., ...)" condition for this property. */
public WhereCondition in(Object... inValues) {
StringBuilder condition = new StringBuilder(" IN (");
SqlUtils.appendPlaceholders(condition, inValues.length).append(')');
return new PropertyCondition(this, condition.toString(), inValues);
}
/** Creates an "IN (..., ..., ...)" condition for this property. */
public WhereCondition in(Collection> inValues) {
return in(inValues.toArray());
}
/** Creates an "NOT IN (..., ..., ...)" condition for this property. */
public WhereCondition notIn(Object... notInValues) {
StringBuilder condition = new StringBuilder(" NOT IN (");
SqlUtils.appendPlaceholders(condition, notInValues.length).append(')');
return new PropertyCondition(this, condition.toString(), notInValues);
}
/** Creates an "NOT IN (..., ..., ...)" condition for this property. */
public WhereCondition notIn(Collection> notInValues) {
return notIn(notInValues.toArray());
}
/** Creates an "greater than ('>')" condition for this property. */
public WhereCondition gt(Object value) {
return new PropertyCondition(this, ">?", value);
}
/** Creates an "less than ('<')" condition for this property. */
public WhereCondition lt(Object value) {
return new PropertyCondition(this, "", value);
}
/** Creates an "greater or equal ('>=')" condition for this property. */
public WhereCondition ge(Object value) {
return new PropertyCondition(this, ">=?", value);
}
/** Creates an "less or equal ('<=')" condition for this property. */
public WhereCondition le(Object value) {
return new PropertyCondition(this, "<=?", value);
}
/** Creates an "IS NULL" condition for this property. */
public WhereCondition isNull() {
return new PropertyCondition(this, " IS NULL");
}
/** Creates an "IS NOT NULL" condition for this property. */
public WhereCondition isNotNull() {
return new PropertyCondition(this, " IS NOT NULL");
}
}
更多内容
1. GreenDao源码分析及使用GreenDao实现静态数据缓存
2. Android数据存储之GreenDao 3.0 详解
3. Android | 分析greenDAO 3.2实现原理
4. ORM对象关系映射之GreenDAO源码解析