ORM对象关系映射之GreenDAO源码解析
2015-09-15 16:21
363 查看
上一篇我们学习了GreenDAO的CRUD基本操作,可以说是非常的方便的,而且GreenDAO的效率和性能远远高于其它两款流行的ORM框架,下面是我从官网找的一副它们三个ORM框架之间的性能测试的直观图:
那么这篇我们就从源码的角度来学习GreenDAO更深层次的工作原理。
从上篇我们知道,如果Android项目中要使用GreenDAO框架,需要先创建一个Java项目用于生成实体类和DAO类,然后在Android项目中使用这些类,在此过程中分别需要对Android项目添加GreenDAO的核心包依赖和对Java项目添加generator包依赖,所以解析GreenDAO的源码需要解析两部分,而这里只解析GreenDAO核心包在Android项目中的工作原理,generator包中的原理很简单,总的来说有四个作用:就是用于生成实体类、DAO类、建立多表之间的关联以及配置实体类的接口和序列化功能(后面的两个功能后续会讲到)。
而在Android项目中用到的最核心的四个类就是:DaoMaster、DaoSession、实体类、实体Dao类。当然还有与CRUD操作密切联系的Property类(Android项目中的核心包和Java项目中的generator包分别都有这个类,不过这两个类作用分别不同,核心包中的主要是针对实体类的属性的,而generator包中的主要是针对表中的字段的)、QueryBuilder类,也至关重要,不过这两个类相信看下源码就懂了,就不多叙述了,而主要讲解这四个核心类。
而DevOpenHelper对象又是什么呢?我们都知道在使用SQLite的时候,我们必须通过继承SQLiteOpenHelper类并且实现它内部的一些方法来创建数据库,而这里仅仅通过DevOpenHelper类就成功创建了一个文件名为”students-db”的数据表,那么内部又是怎么实现的呢?我们可以看看DaoMaster类的源码(以上一篇生成的为例讲):
从DaoMaster中我们可以发现,DaoMaster除了具有创建表和删除表的两个功能外,还有两个内部类,分别为OpenHelper和DevOpenHelper,而DevOpenHelper继承自OpenHelper,而OpenHelper继承自SQLiteOpenHelper,而重写的
发现它内部就是通过sql语句来创建表的,只不过GreenDAO帮我们封装好了,而且你会发现删除表其实也一样:
好了,现在我们知道了通过DevOpenHelper是怎么创建表的,而细心的同学会发现在DevOpenHelper类中实现了
看这个类的代码,其中最让我们受关注的无非就是这一行了
这里定义了一个Map集合,Key是继承自AbstractDao类的字节码对象,Value则为DaoConfig对象,而往这个Map集合中put数据是通过这个方法
所以Map的功能现在很清楚了,就是为每一个EntityDao字节码对象建立与之对应的db数据库的映射关系,从而管理所有的EntityDao类。而这个方法在哪里调用了呢?我们回到DaoMaster的源码中,发现在DaoMaster类的构造方法中调用了,并且传入了
就那么几行,其中最主要的一个方法就是通过
这个正是从在DaoMaster创建的Map集合中取出
好了,接下来就是看看它的父类了:
这个类比较长,所以我删除了几个方法,这不影响理解的
可以看到它的父类中,大部分方法都是进行CRUD操作的,而事实上我们在进行CRUD操作都是通过StudentDao对象来进行的,实际上这两种做法没有区别,因为它内部本身就是通过dao对象来进行CRUD操作的,大家看看这些方法的返回值就知道了。
到此,我们只看到了DaoSession源码表面上的功能,这些功能就是它管理了指定模式下所有可用的DAO对象,并且提供了getter方法供我们得到这些DAO对象,它还提供了一些CRUD方法。实际上DaoSession和StudentDao在调用CRUD的方法进行CRUD操作时,其中的查询操作就是最特别的,为什么呢?原因是GreenDao在查询这块加了缓存,有趣吧,GreenDao在查询时使用了弱引用
这个缓存的代码是在
其中
Property源码如下:
而AbstractDao源码中主要是一些CRUD方法和其它的一些方法:
源码太长了,避免影响篇幅,我删了一部分
好了,核心类已经介绍完了,下面梳理一下它们主要做了什么事。
那么这篇我们就从源码的角度来学习GreenDAO更深层次的工作原理。
GreenDAO的工作原理图解:
从上篇我们知道,如果Android项目中要使用GreenDAO框架,需要先创建一个Java项目用于生成实体类和DAO类,然后在Android项目中使用这些类,在此过程中分别需要对Android项目添加GreenDAO的核心包依赖和对Java项目添加generator包依赖,所以解析GreenDAO的源码需要解析两部分,而这里只解析GreenDAO核心包在Android项目中的工作原理,generator包中的原理很简单,总的来说有四个作用:就是用于生成实体类、DAO类、建立多表之间的关联以及配置实体类的接口和序列化功能(后面的两个功能后续会讲到)。
而在Android项目中用到的最核心的四个类就是:DaoMaster、DaoSession、实体类、实体Dao类。当然还有与CRUD操作密切联系的Property类(Android项目中的核心包和Java项目中的generator包分别都有这个类,不过这两个类作用分别不同,核心包中的主要是针对实体类的属性的,而generator包中的主要是针对表中的字段的)、QueryBuilder类,也至关重要,不过这两个类相信看下源码就懂了,就不多叙述了,而主要讲解这四个核心类。
四个核心类:
这四个核心类的功能体系如下图所示:DaoMaster
我们知道在使用GreenDAO时候,我们的入口点就是通过DaoMaster的静态内部类DevOpenHelper来创建一个DevOpenHelper对象DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "students-db", null);
而DevOpenHelper对象又是什么呢?我们都知道在使用SQLite的时候,我们必须通过继承SQLiteOpenHelper类并且实现它内部的一些方法来创建数据库,而这里仅仅通过DevOpenHelper类就成功创建了一个文件名为”students-db”的数据表,那么内部又是怎么实现的呢?我们可以看看DaoMaster类的源码(以上一篇生成的为例讲):
public class DaoMaster extends AbstractDaoMaster { public static final int SCHEMA_VERSION = 1; /** Creates underlying database table using DAOs. */ public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) { StudentDao.createTable(db, ifNotExists); } /** Drops underlying database table using DAOs. */ public static void dropAllTables(SQLiteDatabase db, boolean ifExists) { StudentDao.dropTable(db, ifExists); } public static abstract class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, String name, CursorFactory factory) { super(context, name, factory, SCHEMA_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); createAllTables(db, false); } } /** WARNING: Drops all table on Upgrade! Use only during development. */ 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); } } public DaoMaster(SQLiteDatabase db) { super(db, SCHEMA_VERSION); registerDaoClass(StudentDao.class); } public DaoSession newSession() { return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); } public DaoSession newSession(IdentityScopeType type) { return new DaoSession(db, type, daoConfigMap); } }
从DaoMaster中我们可以发现,DaoMaster除了具有创建表和删除表的两个功能外,还有两个内部类,分别为OpenHelper和DevOpenHelper,而DevOpenHelper继承自OpenHelper,而OpenHelper继承自SQLiteOpenHelper,而重写的
onCreate()方法中调用了
createAllTables(db,false);方法来创建数据表,而
createAllTables()方法中是通过调用StudentDao静态方法来创建表的
StudentDao.createTable(db, ifNotExists);我们点进这个方法中去看个究竟:
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 }
发现它内部就是通过sql语句来创建表的,只不过GreenDAO帮我们封装好了,而且你会发现删除表其实也一样:
public static void dropTable(SQLiteDatabase db, boolean ifExists) { String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"STUDENT\""; db.execSQL(sql); }
好了,现在我们知道了通过DevOpenHelper是怎么创建表的,而细心的同学会发现在DevOpenHelper类中实现了
onUpgrade()方法,就是更新数据库的方法,它在更新数据表的时候会把以前的数据表删除后再重新创建,所以这个你必须注意,当我们在利用GreenDAO更新数据表的时候,如果你想以前表中的数据保存下来的话,我们必须自己封装一个方法。接下来就是
newSession()方法了,这个当然就是得到DaoSession实例了,关于DaoSession实例,GreenDAO官方建议不要重新创建新的实例,保持一个单例的引用即可。好了,DaoMaster源码看完了,接下来就是看它的父类
AbstractDaoMaster的源码了,它的源码如下:
public abstract class AbstractDaoMaster { protected final SQLiteDatabase db; protected final int schemaVersion; protected final Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap; public AbstractDaoMaster(SQLiteDatabase db, int schemaVersion) { this.db = db; this.schemaVersion = schemaVersion; daoConfigMap = new HashMap<Class<? extends AbstractDao<?, ?>>, DaoConfig>(); } 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); }
看这个类的代码,其中最让我们受关注的无非就是这一行了
protected final Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> daoConfigMap;
这里定义了一个Map集合,Key是继承自AbstractDao类的字节码对象,Value则为DaoConfig对象,而往这个Map集合中put数据是通过这个方法
registerDaoClass():
protected void registerDaoClass(Class<? extends AbstractDao<?, ?>> daoClass) { DaoConfig daoConfig = new DaoConfig(db, daoClass); daoConfigMap.put(daoClass, daoConfig); }
所以Map的功能现在很清楚了,就是为每一个EntityDao字节码对象建立与之对应的db数据库的映射关系,从而管理所有的EntityDao类。而这个方法在哪里调用了呢?我们回到DaoMaster的源码中,发现在DaoMaster类的构造方法中调用了,并且传入了
Student.class,所以我们在创建DaoMaster对象的时候也同时为EntityDao类和相应的数据库db建立好了关联。
DaoSession
从上面可知DaoSession对象是通过master.newSession();创建的。我们看看DaoSession源码,发现它也有一个抽象的父类AbstractDaoSession,我们来看看DaoSession的源码:
public class DaoSession extends AbstractDaoSession { private final DaoConfig studentDaoConfig; private final StudentDao studentDao; public DaoSession(SQLiteDatabase db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, 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; } }
就那么几行,其中最主要的一个方法就是通过
getStudentDao()来得到StudentDao实例,而创建一个StudentDao对象正是在DaoSession的构造方法中,其中有这么一行:
studentDaoConfig = daoConfigMap.get(StudentDao.class).clone();
这个正是从在DaoMaster创建的Map集合中取出
key为
StudentDao.class的DaoConfig对象,刚刚就说了Map集合中保寸了StudentDao类对应的数据库db的关系映射,而这个DaoConfig对象正是管理了对应的db对象。然后把这个DaoConfig传给
StudentDao(studentDaoConfig, this),所以这就说明了我们使用StudentDao对象来进行数据库上的CRUD操作而对应的数据库也会变化的原因,这个过程实际上就是在间接操作数据库。
好了,接下来就是看看它的父类了:
这个类比较长,所以我删除了几个方法,这不影响理解的
public class AbstractDaoSession { private final SQLiteDatabase db; private final Map<Class<?>, AbstractDao<?, ?>> entityToDao; public AbstractDaoSession(SQLiteDatabase db) { this.db = db; this.entityToDao = new HashMap<Class<?>, AbstractDao<?, ?>>(); } protected <T> void registerDao(Class<T> entityClass, AbstractDao<T, ?> dao) { entityToDao.put(entityClass, dao); } /** Convenient call for {@link AbstractDao#insert(Object)}. */ public <T> long insert(T entity) { @SuppressWarnings("unchecked") AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass()); return dao.insert(entity); } /** Convenient call for {@link AbstractDao#insertOrReplace(Object)}. */ public <T> long insertOrReplace(T entity) { @SuppressWarnings("unchecked") AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass()); return dao.insertOrReplace(entity); } /** Convenient call for {@link AbstractDao#refresh(Object)}. */ public <T> void refresh(T entity) { @SuppressWarnings("unchecked") AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass()); dao.refresh(entity); } /** Convenient call for {@link AbstractDao#update(Object)}. */ public <T> void update(T entity) { @SuppressWarnings("unchecked") AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass()); dao.update(entity); } //... /** Convenient call for {@link AbstractDao#delete(Object)}. */ public <T> void delete(T entity) { @SuppressWarnings("unchecked") AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entity.getClass()); dao.delete(entity); } /** Convenient call for {@link AbstractDao#deleteAll()}. */ public <T> void deleteAll(Class<T> entityClass) { @SuppressWarnings("unchecked") AbstractDao<T, ?> dao = (AbstractDao<T, ?>) getDao(entityClass); dao.deleteAll(); } /** Convenient call for {@link AbstractDao#load(Object)}. */ public <T, K> T load(Class<T> entityClass, K key) { @SuppressWarnings("unchecked") AbstractDao<T, K> dao = (AbstractDao<T, K>) 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); } }
可以看到它的父类中,大部分方法都是进行CRUD操作的,而事实上我们在进行CRUD操作都是通过StudentDao对象来进行的,实际上这两种做法没有区别,因为它内部本身就是通过dao对象来进行CRUD操作的,大家看看这些方法的返回值就知道了。
到此,我们只看到了DaoSession源码表面上的功能,这些功能就是它管理了指定模式下所有可用的DAO对象,并且提供了getter方法供我们得到这些DAO对象,它还提供了一些CRUD方法。实际上DaoSession和StudentDao在调用CRUD的方法进行CRUD操作时,其中的查询操作就是最特别的,为什么呢?原因是GreenDao在查询这块加了缓存,有趣吧,GreenDao在查询时使用了弱引用
WeakReference,假如第一次查询时候我查询了小明这个Student的数据,那么它将把小明加入一个
SparseArray<WeakReference<Q>>的集合中,下次如果再次查询小明这个学生的时候,将立即会返回这个引用从而不必再查询数据库(前提是GC还没回收这些引用)。
这个缓存的代码是在
AbstractQueryData类中,如下:
SparseArray<WeakReference<Q>> queriesForThreads = new SparseArray<WeakReference<Q>>(); //... Q forCurrentThread() { int threadId = Process.myTid(); synchronized (queriesForThreads) { WeakReference<Q> queryRef = queriesForThreads.get(threadId); Q query = queryRef != null ? queryRef.get() : null; if (query == null) { gc(); query = createQuery(); queriesForThreads.put(threadId, new WeakReference<Q>(query)); } else { System.arraycopy(initialValues, 0, query.parameters, 0, initialValues.length); } return query; } }
Entity(实体类)
对于实体类,这没什么可讲的,就是一个Bean,一个实体类对应一张表,实体类里面有对应各个字段的getter和setter方法EntityDao(实体Dao类)
同样,它也有一个抽象的父类AbstractDao,我们先看看StudentDao类的源码:public class StudentDao extends AbstractDao<Student, Long> {
public static final String TABLENAME = "STUDENT";
/**
* Properties of entity Student.<br/>
* 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"); } }
而AbstractDao源码中主要是一些CRUD方法和其它的一些方法:
源码太长了,避免影响篇幅,我删了一部分
public abstract class AbstractDao<T, K> { protected final SQLiteDatabase db; protected final DaoConfig config; protected IdentityScope<K, T> identityScope; protected IdentityScopeLong<T> identityScopeLong; protected TableStatements statements; protected final AbstractDaoSession session; protected final int pkOrdinal; public AbstractDao(DaoConfig config) { this(config, null); } @SuppressWarnings("unchecked") public AbstractDao(DaoConfig config, AbstractDaoSession daoSession) { this.config = config; this.session = daoSession; db = config.db; identityScope = (IdentityScope<K, T>) config.getIdentityScope(); if (identityScope instanceof IdentityScopeLong) { identityScopeLong = (IdentityScopeLong<T>) identityScope; } statements = config.statements; pkOrdinal = config.pkProperty != null ? config.pkProperty.ordinal : -1; } public AbstractDaoSession getSession() { return session; } TableStatements getStatements() { return config.statements; } public String getTablename() { return config.tablename; } public Property[] getProperties() { return config.properties; } public Property getPkProperty() { return config.pkProperty; } public String[] getAllColumns() { return config.allColumns; } public String[] getPkColumns() { return config.pkColumns; } public String[] getNonPkColumns() { return config.nonPkColumns; } //... /** * Deletes the given entities in the database using a transaction. * * @param entities * The entities to delete. */ public void deleteInTx(Iterable<T> entities) { deleteInTxInternal(entities, null); } /** * Deletes the given entities in the database using a transaction. * * @param entities * The entities to delete. */ public void deleteInTx(T... entities) { deleteInTxInternal(Arrays.asList(entities), null); } /** * Deletes all entities with the given keys in the database using a transaction. * * @param keys * Keys of the entities to delete. */ public void deleteByKeyInTx(Iterable<K> keys) { deleteInTxInternal(null, keys); } /** * Deletes all entities with the given keys in the database using a transaction. * * @param keys * Keys of the entities to delete. */ public void deleteByKeyInTx(K... keys) { deleteInTxInternal(null, Arrays.asList(keys)); } /** Resets all locally changed properties of the entity by reloading the values from the database. */ public void refresh(T entity) { assertSinglePk(); K key = getKeyVerified(entity); String sql = statements.getSelectByKey(); String[] keyArray = new String[] { key.toString() }; Cursor cursor = db.rawQuery(sql, keyArray); try { boolean available = cursor.moveToFirst(); if (!available) { throw new DaoException("Entity does not exist in the database anymore: " + entity.getClass() + " with key " + key); } else if (!cursor.isLast()) { throw new DaoException("Expected unique result, but count was " + cursor.getCount()); } readEntity(cursor, entity, 0); attachEntity(key, entity, true); } finally { cursor.close(); } } public void update(T entity) { assertSinglePk(); SQLiteStatement stmt = statements.getUpdateStatement(); if (db.isDbLockedByCurrentThread()) { synchronized (stmt) { updateInsideSynchronized(entity, stmt, true); } } else { // Do TX to acquire a connection before locking the stmt to avoid deadlocks db.beginTransaction(); try { synchronized (stmt) { updateInsideSynchronized(entity, stmt, true); } db.setTransactionSuccessful(); } finally { db.endTransaction(); } } } public QueryBuilder<T> queryBuilder() { return QueryBuilder.internalCreate(this); } }
好了,核心类已经介绍完了,下面梳理一下它们主要做了什么事。
GreenDAO工作原理
我们首先来看看使用GreenDAO的基本步骤://生成数据库文件,名为students-db DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "students-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(student); //...
相关文章推荐
- A look at the PowerVR graphics architecture: Tile-based rendering
- 黑马程序员Activity 介绍
- linux基础编程 共享内存 使用内存映射接口mmap系统调用 blog.csdn.net/ghostyu/article/details/7736733
- Uva 10375 Choose and divide 素数唯一分解定理
- ORM对象关系映射之GreenDAO源码解析
- ”增量更新“Java程序员转安卓开发
- struts2 标签
- Ruby on Rails服务器文件上传
- SQL触发器实例
- A标签伪类
- PHP mysqli(数据库操作)
- Vmware vSphere 5.0 vSphere网络原理及vSwitch简介
- C++内存管理
- linux之sed用法
- vim 的使用方法
- 配置IIS服务器支持Sencha Touch
- 使用Jenkins配置自动化构建
- iOS开发之 手势
- cocos2dx-3.X中对事件处理分析(1)
- mongodb备份还原脚本