GreenDao学习笔记——初始化和增删改查

GreenDao的初始化:

        DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
        db = helper.getWritableDatabase();
        daoMaster = new DaoMaster(db);
        daoSession = daoMaster.newSession();
        noteDao = daoSession.getNoteDao();

这个代码主要是用于建立数据库和初始化一些变量,如初始化NoteDao的父类AbstractDao的变量和参数,

    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;

其中:
SQLiteDatabase db:我们建立的数据库对象;
DaoConfig config:用于保存数据访问对象Dao的基本数据;
TableStatements statements:用于生成操作数据表的SQL statements;
identityScope:greendao有一个缓存机制,即把用户插入,更改或查找的实体保存在内存中,当用户下一次查找时先从内存中查找,如果不存在再从数据库中查找,当表的主键是数字类型的时候,identityScopeLong将不会空,并且指向identityScope。
在初始每个dao对象的DaoConfig的时候,判断主键是否是数字类型,

 if (pkProperty != null) {
                Class<?> type = pkProperty.type;
                keyIsNumeric = type.equals(long.class) || type.equals(Long.class) || type.equals(int.class)
                        || type.equals(Integer.class) || type.equals(short.class) || type.equals(Short.class)
                        || type.equals(byte.class) || type.equals(Byte.class);
            } else {
                keyIsNumeric = false;
            }

如果主键是数字类型的话,initIdentityScope时identityScope 初始化IdentityScopeLong类型,

public void initIdentityScope(IdentityScopeType type) {
        if (type == IdentityScopeType.None) {
            identityScope = null;
        } else if (type == IdentityScopeType.Session) {
            if (keyIsNumeric) {
                identityScope = new IdentityScopeLong();
            } else {
                identityScope = new IdentityScopeObject();
            }
        } else {
            throw new IllegalArgumentException("Unsupported type: " + type);
        }
    }

然后在数据操作对象的父类的构造方法中,将identityScopeLong 指向identityScope,

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;
    }

然后,所有主键为数字类型dao对象获取内存中缓存对象的都会调用IdentityScopeLong中的get方法,

 public T get(Long key) {
        return get2(key);
    }

所以,如果主键不是long类型的话就会报类型转换错误!
错误的贴图。。。。
当然,我们可以自己控制是否使用缓存功能,在DaoMaster中有两个初始化DaoSession的方法,

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

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

我们可以使用第二个构造方法并传入type为IdentityScopeType.None,这样initIdentityScope方法就会包identityScope 赋为空值,即不使用缓存机制。

public void initIdentityScope(IdentityScopeType type) {
        if (type == IdentityScopeType.None) {
            identityScope = null;
        } else if (type == IdentityScopeType.Session) {
            if (keyIsNumeric) {
                identityScope = new IdentityScopeLong();
            } else {
                identityScope = new IdentityScopeObject();
            }
        } else {
            throw new IllegalArgumentException("Unsupported type: " + type);
        }
    }

在使用greendao缓存机制的情况下,如果数据表的主键是数字类型的话,一定要使用long类型,不然不会报类型转换错误

插入对象insert:

        Note note = new Note(null, noteText, comment, new Date());
        getNoteDao().insert(note);

greendao在底层的实现是:

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

首先判断数据库是否被当前线程锁住,如果是,绑定参数并执行插入,如果不是,则开启一个事务,然后绑定参数并执行插入。
其中,NoteDao重写了父类AbstractDao的bindValues方法,进行相对应对象数据的绑定,
updateKeyAfterInsertAndAttach(entity, rowId, true)是为了更新自增主键的id,将实体放入缓存中。

删除对象delete:

noteDao.deleteByKey(id);

底层源码的实现是:

 public void deleteByKey(K key) {
        assertSinglePk();
        SQLiteStatement stmt = statements.getDeleteStatement();
        if (db.isDbLockedByCurrentThread()) {
            synchronized (stmt) {
                deleteByKeyInsideSynchronized(key, stmt);
            }
        } else {
            // Do TX to acquire a connection before locking the stmt to avoid deadlocks
            db.beginTransaction();
            try {
                synchronized (stmt) {
                    deleteByKeyInsideSynchronized(key, stmt);
                }
                db.setTransactionSuccessful();
            } finally {
                db.endTransaction();
            }
        }
        if (identityScope != null) {
            identityScope.remove(key);
        }
    }

删除对象与插入对象相似,删除操作目前仅支持操作单一主键的表,assertSinglePk()是判断对象是否是单一主键,若不是则抛出错误,

if (identityScope != null) {
            identityScope.remove(key);
        }

判断是否使用缓存机制,是的话删除缓存中的实体。

修改对象update:

noteDao.insertOrReplace(note);

底层源码的实现是:

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

同样,updateKeyAfterInsertAndAttach(entity, rowId, true)同插入操作。

查找对象Search:
greendao提供提供多种查找方式进行查找。

List<Note> list = getNoteDao().queryBuilder().where(NoteDao.Properties.Text.eq("test")).build().list();
Note note = noteDao.load((long) 1);

查找对象的实现实现是原理是传入多个限制条件,然后在底层代码中拼接sql查询语句进行查询,然后在转换成相对应的对象。查询的机制跟其他操作方式一样,如果有使用greendao的缓存机制,则先从缓存中获取,再从数据库获取,如果没有使用缓存机制,则直接从数据库中获取。
如果需要使用更复杂的查询方法的话,可以查看Property类和QueryBuilder的源码,greendao提供多种方式的拼接,可以组成日常开发中经常用到的查询语句。
需要一提的是greendao的懒加载功能:

参考资料:
http://greenrobot.org/
http://blog.csdn.net/xushuaic/article/details/24434881
http://blog.csdn.net/xushuaic/article/details/24438841
http://blog.csdn.net/xushuaic/article/details/24496191

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值