美文网首页
GreenDao详解二

GreenDao详解二

作者: My_Hubery | 来源:发表于2018-07-31 15:45 被阅读0次

在上一篇GreenDao详解一中有讲到,GreenDaobuild的时候,会自动生成DaoMaster, DaoSession,xxDao三个文件,我们通过上一篇的知识了解到,插入一条数据可以这样写:

private void insertUser(User user){
      //DaoMaster daoMaster = DbManager.getDaoMaster(mContext);
        DaoMaster.DevOpenHelper mDevOpenHelper = new DaoMaster.DevOpenHelper(mContext, DB_NAME);
        DaoMaster mDaoMaster = new DaoMaster(mDevOpenHelper.getWritableDb());
        UserDao userDao = daoMaster.newSession().getUserDao();
        userDao.insert(user);
}

先来理一理他们的调用关系:
DaoMaster中创建并获得DaoSession,而DaoSession创建和管理xxDao,而xxDao则对xxEntity进行数据的CRUD操作。为了直观,这里给出了一个关系图:

GreenDao_Generator.png

DaoMaster

DaoMaster是对数据库进行相关操作的一个封装类,内部包括了创建表,删除表的方法,还包括两个静态抽象类OpenHelperDevOpenHelperOpenHelper继承于SQLiteOpenHelper,通过源码我们看到最终会调用到createAllTabes方法来创建数据库中的表;而DevOpenHelper继承于OpenHelper,主要通过onUpgrade方法用于数据库的升级,另外,它还包含一个newSession()方法,在方法内返回一个DaoSession对象,DaoSession是连接GreenDao框架到SQLite数据库的桥梁,通过该对象我们可以得到一个与xxx表相关的操作对象xxxDao
我们先来看看DaoMaster的源码:

public class DaoMaster extends AbstractDaoMaster {
    public static final int SCHEMA_VERSION = 1;

    /** Creates underlying database table using DAOs. */
    public static void createAllTables(Database db, boolean ifNotExists) {
        UserDao.createTable(db, ifNotExists);
    }

    /** Drops underlying database table using DAOs. */
    public static void dropAllTables(Database db, boolean ifExists) {
        UserDao.dropTable(db, ifExists);
    }

    /**
     * WARNING: Drops all table on Upgrade! Use only during development.
     * Convenience method using a {@link DevOpenHelper}.
     */
    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);
        registerDaoClass(UserDao.class);
    }

    public DaoSession newSession() {
        return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
    }

    public DaoSession newSession(IdentityScopeType type) {
        return new DaoSession(db, type, daoConfigMap);
    }

    /**
     * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} -
     */
    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);
        }
    }

    /** WARNING: Drops all table on Upgrade! Use only during development. */
    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构造函数中,会调用父类AbstractDaoMaster的构造函数和registerDaoClass方法:

 public DaoMaster(Database db) {
      super(db, SCHEMA_VERSION);
      registerDaoClass(UserDao.class);
 }
 public AbstractDaoMaster(Database 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);
   }

上面的代码中维护了一个daoConfigMap的集合,它是以daoClass为key,DaoConfig为Value的集合。
DaoConfig源码:

public final class DaoConfig implements Cloneable {

    public final Database db;
    public final String tablename;
    public final Property[] properties;

    public final String[] allColumns;
    public final String[] pkColumns;
    public final String[] nonPkColumns;

    /** Single property PK or null if there's no PK or a multi property PK. */
    public final Property pkProperty;
    public final boolean keyIsNumeric;
    public final TableStatements statements;

    private IdentityScope<?, ?> identityScope;

    public DaoConfig(Database db, Class<? extends AbstractDao<?, ?>> daoClass) {
        this.db = db;
        try {
            this.tablename = (String) daoClass.getField("TABLENAME").get(null);
            Property[] properties = reflectProperties(daoClass);
            //省略部分代码
            //pkColumns对应表中主键的集合,allColumns表中所有字段集合
            statements = new TableStatements(db, tablename, allColumns, pkColumns);
            //省略部分代码
        } catch (Exception e) {
            throw new DaoException("Could not init DAOConfig", e);
        }
    }

    private static Property[] reflectProperties(Class<? extends AbstractDao<?, ?>> daoClass)
            throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
        Class<?> propertiesClass = Class.forName(daoClass.getName() + "$Properties");
        Field[] fields = propertiesClass.getDeclaredFields();

        ArrayList<Property> propertyList = new ArrayList<Property>();
        final int modifierMask = Modifier.STATIC | Modifier.PUBLIC;
        for (Field field : fields) {
            // There might be other fields introduced by some tools, just ignore them (see issue #28)
            if ((field.getModifiers() & modifierMask) == modifierMask) {
                Object fieldValue = field.get(null);
                if (fieldValue instanceof Property) {
                    propertyList.add((Property) fieldValue);
                }
            }
        }

        Property[] properties = new Property[propertyList.size()];
        for (Property property : propertyList) {
            if (properties[property.ordinal] != null) {
                throw new DaoException("Duplicate property ordinals");
            }
            properties[property.ordinal] = property;
        }
        return properties;
    }
  //  //省略部分代码
}

DaoConfig主要通过传入的daoClass参数并通过反射去拿到对应表中的相应信息,并通过TableStatements(db, tablename, allColumns, pkColumns);创建一个TableStatements对象。而这个TableStatements对象注释上面有写是为特定表创建SQL语句的Help类,而该对象会在AbstractDao类中使用,以方便继承了AstractDao的类使用。

DaoSession

DaoSession用于获得能够操作数据库的XXDao对象,它建立了与SQLite数据库之间的连接(会话),其中,getUserDao方法用于返回相UserDao的对象,我们在操作数据库的时候,通过XXDao对象去对数据库数据进行CRUD操作。

public class DaoSession extends AbstractDaoSession {
    private final DaoConfig userDaoConfig;
    private final UserDao userDao;
    public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
            daoConfigMap) {
        super(db);
        userDaoConfig = daoConfigMap.get(UserDao.class).clone();
        userDaoConfig.initIdentityScope(type);
        userDao = new UserDao(userDaoConfig, this);
        registerDao(User.class, userDao);
    }
    
    public void clear() {
        userDaoConfig.clearIdentityScope();
    }

    public UserDao getUserDao() {
        return userDao;
    }
}

DaoSession 继承于AbstractDaoSession,而AbstractDaoSession里面实现了很多操作数据库表的方法,而这些方法最后会调用到AbstractDao中的相关方法,现在我们来看看AbstractDaoSession的实现:

public class AbstractDaoSession {
    private final Database db;
    private final Map<Class<?>, AbstractDao<?, ?>> entityToDao;

    private volatile RxTransaction rxTxPlain;
    private volatile RxTransaction rxTxIo;

    public AbstractDaoSession(Database 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);
    }
    //省略部分代码
}

XXDao

XXDao通过GreenDao生成器生成的数据库操作类,它继承于AbstractDao,从而可以调用AbstractDao中对数据库表进行CRUD的方法。

public class UserDao extends AbstractDao<User, Long> {

    public static final String TABLENAME = "USER";

    /**
     * Properties of entity User.<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 Grade = new Property(2, int.class, "grade", false, "GRADE");
        public final static Property Age = new Property(3, Integer.class, "age", false, "AGE");
    }


    public UserDao(DaoConfig config) {
        super(config);
    }
    
    public UserDao(DaoConfig config, DaoSession daoSession) {
        super(config, daoSession);
    }

    /** Creates the underlying database table. */
    public static void createTable(Database db, boolean ifNotExists) {
        String constraint = ifNotExists? "IF NOT EXISTS ": "";
        db.execSQL("CREATE TABLE " + constraint + "\"USER\" (" + //
                "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
                "\"NAME\" TEXT," + // 1: name
                "\"GRADE\" INTEGER NOT NULL ," + // 2: grade
                "\"AGE\" INTEGER);"); // 3: age
    }

    /** Drops the underlying database table. */
    public static void dropTable(Database db, boolean ifExists) {
        String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"USER\"";
        db.execSQL(sql);
    }

    @Override
    protected final void bindValues(DatabaseStatement stmt, User entity) {
        stmt.clearBindings();
 
        Long id = entity.getId();
        if (id != null) {
            stmt.bindLong(1, id);
        }
 
        String name = entity.getName();
        if (name != null) {
            stmt.bindString(2, name);
        }
        stmt.bindLong(3, entity.getGrade());
 
        Integer age = entity.getAge();
        if (age != null) {
            stmt.bindLong(4, age);
        }
    }

    @Override
    protected final void bindValues(SQLiteStatement stmt, User entity) {
        stmt.clearBindings();
 
        Long id = entity.getId();
        if (id != null) {
            stmt.bindLong(1, id);
        }
 
        String name = entity.getName();
        if (name != null) {
            stmt.bindString(2, name);
        }
        stmt.bindLong(3, entity.getGrade());
 
        Integer age = entity.getAge();
        if (age != null) {
            stmt.bindLong(4, age);
        }
    }
  //省略部分代码
}

xxDao里面提供了创建数据表的createTable方法,提供了dropTable方法,使用bindValues进行绑定。
现在我们再来看看AbstractDao的代码:

public abstract class AbstractDao<T, K> {
    //省略部分代码
    public long insert(T entity) {
        return executeInsert(entity, statements.getInsertStatement(), true);
    }

    private long executeInsert(T entity, DatabaseStatement stmt, boolean setKeyAndAttach) {
        long rowId;
        if (db.isDbLockedByCurrentThread()) {
            rowId = insertInsideTx(entity, stmt);
        } else {
            // Do TX to acquire a connection before locking the stmt to avoid deadlocks
            db.beginTransaction();
            try {
                rowId = insertInsideTx(entity, stmt);
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
        }
        if (setKeyAndAttach) {
            updateKeyAfterInsertAndAttach(entity, rowId, true);
        }
        return rowId;
    }

     private long insertInsideTx(T entity, DatabaseStatement stmt) {
        synchronized (stmt) {
            if (isStandardSQLite) {
                SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
                bindValues(rawStmt, entity);
                return rawStmt.executeInsert();
            } else {
                bindValues(stmt, entity);
                return stmt.executeInsert();
            }
        }
    }
  //省略部分代码
}

我们看到AbstractDao类中定义了很多操作数据表的方法,在这里我们截取了insert方法,我们看到外部调用的insert方法实际调用的是executeInsert,而这个方法中还会继续调用insertInsideTx方法,方法内通过isStandardSQLite变量去判断是调用sqlite中的executeInsert还是greenDao中的executeInsert。走到这里基本就操作数据表中简单的看了一遍。

GreenDao的对数据表的CRUD操作GreenDao详解一已经简单说明了,在这里就不一一重复了。

相关文章

  • GreenDao 问题集合

    GreenDao 详解 GreenDao 简介 GreenDAO 是一款开源的面向 Android 的轻便、快捷的...

  • GreenDao3.0使用

    史上最高效的ORM方案——GreenDao3.0详解 GreenDao3.0简单使用 关于GreenDao gre...

  • GreenDao详解二

    在上一篇GreenDao详解一中有讲到,GreenDao在build的时候,会自动生成DaoMaster, Dao...

  • 好文章推荐

    好文章推荐 1.Android数据存储之GreenDao 3.0 详解 2.Dagger2 使用详解 3.stet...

  • GreenDAO详解

    简介 greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。官方文档 项目...

  • Android之greenDao使用(非原创)

    文章大纲 一、greenDao简介二、greenDao实战三、项目源码下载四、参考文章 一、greenDao简介 ...

  • GreenDao详解一

    GreenDao是一个对象关系型框架,也就是我们常说的ORM框架,使用它可以通过操作对象的方式去操作数据库。从而不...

  • GreenDao3.0详解

    GitHub地址:GreenDao 介绍 GreenDao是一款适用于Android的轻量快速ORM,可将对象映射...

  • ORM 框架之 GreenDao(三)多表关联

    个人博客地址 ORM 框架之 GreenDao(一)基本使用 ORM 框架之 GreenDao(二)高级用法 OR...

  • ORM 框架之 GreenDao(二)高级用法

    个人博客地址 ORM 框架之 GreenDao(一)基本使用 ORM 框架之 GreenDao(二)高级用法 OR...

网友评论

      本文标题:GreenDao详解二

      本文链接:https://www.haomeiwen.com/subject/hwlcrftx.html