数据库学习之 GreenDAO 实战

前言

上一篇 对 greenDAO 进行了基本的介绍,包括配置、注解含义、基本的操作。本篇主要对 greenDAO 的增删改查的一些高级用法进行介绍,有时可能业务需求,简单的增删改查可能满足不了,比如数据较大、多表联查,这时就需要学一下 greenDAO 的高级用法。

本篇主要内容,就在这个粗略的草图中。

数据库学习之 GreenDAO 实战_第1张图片
GreenDAO_Structure

1. 建表

对于移动端来说,数据库不会很复杂,毕竟空间和处理能力有限,基本上用到的是一些单独的一张表,或者一对一,一对多这样的表。那我们就来试一下一对多的表。

两张表,一张里面存储班级信息,另一张里面存储学生信息,班级里面有多个学生,这样就建立起一对多的关系。

班级:名字和编号

学生:学号,名字,班级,年龄

班级实体类


@Entity
public class Clazz {

    @Unique
    @Id(autoincrement = true)
    private Long id;

    private String name;

    // 一对多 注解,采用 referencedJoinProperty 方式,clazID 为学生的班级号
    @ToMany(referencedJoinProperty = "clazID")
    private List studentList;
    
    // hash 值由编译时自动生成,使用时只需要 对构造函数注解  @Generated 即可
    @Generated(hash = 1166360579)
    public Clazz() {
    }

    @Generated(hash = 582074864)
    public Clazz(Long id, String name) {
        this.id = id;
        this.name = name;
    }

学生实体类


@Entity(nameInDb = "Student")
public class Student {

    @Unique
    @Id(autoincrement = true)
    private Long id;

    // 修改字段在数据库中的名字
    @Property(nameInDb = "studentID")
    private int studentID;

    private String name;
    
    // 一对多 字段关联 属性
    private long clazID;
    private int age;

    @Generated(hash = 1556870573)
    public Student() {
    }

    @Generated(hash = 435762767)
    public Student(Long id, int studentID, String name, long clazID, int age) {
        this.id = id;
        this.studentID = studentID;
        this.name = name;
        this.clazID = clazID;
        this.age = age;
    }

造数据

    List clazzList = new ArrayList<>();
    List studentList = new ArrayList<>();
    ...
private void initData() {
    int studenId = 10;
    long id = 0;
    for (int i = 1; i < 4; i++) {
        Clazz clazz = new Clazz();
        clazz.setId(new Long(i));
        clazz.setName(i + "班");
        for (int j = 0; j < 5; j++) {
            Student student = new Student();
            student.setAge(18 + j);
            student.setId(id++);
            student.setStudentID(studenId++);
            student.setName("Ralf");
            student.setClazID(clazz.getId());
            studentList.add(student);
        }
        clazzList.add(clazz);
    }
}

建表和准备好数据之后,就可以将数据插入到数据库中。可以使用 insertInTx 这个方法,将数据批量插入到数据库中,后面会讲到封装

/**
     * 插入多条数据
     *
     * @param entities
     */
    public  void inster(List entities) {
        isDaoNull();
        mAbstractDao.insertInTx(entities);
    }

2. 调试

之前调试使用 adb 命令调试,使用原生的查询数据,“select * from table” ,类似于这样的语句。有点麻烦。这里推荐的一个工具 **Android-Debug-Database **

使用这个开源库调试数据库非常方便。

特色:

可视化查看数据库

能够直接对数据库增删改查

可以查看你的应用中所有的shared preferences

使用

在你的build.gradle添加如下:

debugCompile 'com.amitshekhar.android:debug-db:1.0.0'

debugCompile的作用:只在你debug编译时起作用,当你release的时候就没必要使用它了。
下面当你在App启动的时候,你要注意查看下你的logcat,会有这么一行:
D/DebugDB: Open http://XXX.XXX.X.XXX:8080
点击打开浏览器,你就可以看到你的App中的数据库,和 shared preferences

3. 增删改查

3.1 增

// 单条数插入
public long insert(T entity) {}

// 批量插入数据
public void insertInTx(T... entities) {}

public void insertInTx(Iterable entities) {}

public void insertInTx(Iterable entities, boolean setPrimaryKey) {}
// 插入单条数据,如果存在,则替换
public long insertOrReplace(T entity) {}

// 批量插入数据,如果存在,则替换
public void insertOrReplaceInTx(T... entities) {}

public void insertOrReplaceInTx(Iterable entities) {}

public void insertOrReplaceInTx(Iterable entities, boolean setPrimaryKey) {}
// 类似于insertOrReplace()方法,但比它更有效率,因为当key已经存在时,不需要查询直接更新
public void save(T entity) {}

3.2 删

// 删除相应表的全部数据
public void deleteAll() {}

// 删除给定PK的实体。目前,仅支持惟一PK实体。
public void deleteByKey(K key) {}

// 使用事务删除数据库中给定键的所有实体。批量删除。
public void deleteByKeyInTx(K... keys) {}
public void deleteByKeyInTx(Iterable keys) {}

// 删除给定的实体
public void delete(T entity) {}

//使用事务删除数据库中给定的实体。批量删除。每个entity的id属性必须有值,否则报错。其实就是删除与entity主键值相同的数据,entity的其他数据值与表中数据值不一致时,也会删除。
public void deleteInTx(T... entities) {}
public void deleteInTx(Iterable entities) {}

3.3 改

// 更新一条实体数据,entity的id属性必须有值,否则报错。若entity的id值表中不存在时,不会报错。
public void update(T entity) {}

// 更新多条数据,每个entity的id属性必须有值,否则报错。若entity的id值表中不存在时,不会报错。
public void updateInTx(T... entities) {}

public void updateInTx(Iterable entities) {}

3.4 查

普通查询

// 删除指定主键实体
public T load(K key) {}

// 加载给定RowId的实体。传入:key or null。返回:该实体 或 null。
public T loadByRowId(long rowId) {}

// 从数据库加载所有可用的实体
public List loadAll() {}

高级查询

// 原始查询语句
public List queryRaw(String where, String... selectionArg) {}

QueryBuilder

图片

构建 QueryBuilder

QueryBuilder queryBuilder = mDaoSession.queryBuilder(claz);

QueryBuilder 有一系列的方法,其中注意 build() 和 list()方法

数据库学习之 GreenDAO 实战_第2张图片
QueryBuilder

其中,如果使用 build 方法,则可以将得到的 Query 对象作为参数传递给查询方法

// 异步查询,后面详细讲
public AsyncOperation queryList(Query query) {}

另外,也可以使用 QueryBuilder 对象直接查询,使用 list 方法

// 执行查询并将返回一个包含所有entity的list为结果,直接加载在内存中。
public List list() {}

例子

List list = dbUtil.queryBuilder(Student.class)
                        .limit(3)
                        .distinct()
                        .build()
                        .list();

WhereCondition
WhereCondition 对象可以使用下面的对象构建,然后作为参数,WhereCondition 相当于使用原始的查询语句。

between(Object value1, Object value2): BETWEEN … AND …
eq(Object value): equal (‘=’)
notEq(Object value): not equal (‘<>’)
gt(Object value): than (‘>’)
lt(Object value): less than (‘<’)
ge(Object value): greater or equal (‘>=’)
le(Object value): less or equal (‘<=’)
like(String value): LIKE
isNotNull(): IS NOT NULL
isNull(): IS NULL
in(Object… inValues): IN (…, …, …)
notIn(Object… notInValues): NOT IN (…, …, …)
in(Collection< ?> inValues): IN (…, …, …)
notIn(Collection< ?> notInValues): NOT IN (…, …, …)

例子

List list = dbUtil.queryBuilder(Student.class)
        .limit(3)
        .distinct()
        .where(StudentDao.Properties.Id.eq(1))
        .list();

join 多表联查

join 方法很多,下面针对给出的join方法逐个分析,使用时根据查询的需求来决定。

// 通过联合另一个表扩展查询,sourceProperty 和需要联合的表中的 destinationEntityClass 的主键匹配
public  Join join(Property sourceProperty, Class destinationEntityClass) {}

例子

// 构建 QueryBuilder
QueryBuilder queryBuilder = dbUtil.create(Student.class).queryBuilder(Student.class);
//Properties.ClazID和Clazz.class的主键匹配
queryBuilder.join(StudentDao.Properties.ClazID, Clazz.class)
        .where(ClazzDao.Properties.Id.eq(1));

List studentList1 = queryBuilder.list();
// 和上面的 join 方法类似,多了一个参数 destinationProperty,这个属性相当于自己指定主键;也就是说 sourceProperty 和 destinationEntityClass表中的 destinationProperty 字段匹配;但不限与destinationEntityClass的主键,也可以是其他字段
public  Join join(Property sourceProperty, Class destinationEntityClass, Property destinationProperty) {}

例子

// 构建 QueryBuilder
QueryBuilder queryBuilder = dbUtil.create(Student.class).queryBuilder(Student.class);
// 指定主键 ClazzDao.Properties.Id
queryBuilder.join(StudentDao.Properties.ClazID, Clazz.class,ClazzDao.Properties.Id)
        .where(ClazzDao.Properties.Id.eq(1));

List studentList1 = queryBuilder.list();
// 需要查询的表中的主键和联合表中字段匹配,即 destinationProperty
public  Join join(Class destinationEntityClass, Property destinationProperty) {

例子

QueryBuilder queryBuilder1 = dbUtil.create(Clazz.class).queryBuilder(Clazz.class);
// Clazz 班级的主键是学生 Student 表中的外键,即 StudentDao.Properties.ClazID
queryBuilder1.join(Student.class,StudentDao.Properties.ClazID)
        .where(StudentDao.Properties.StudentID.eq(11));

List clazzList = queryBuilder1.list();

多表联查

public  Join join(Join sourceJoin, Property sourceProperty, Class destinationEntityClass,
                               Property destinationProperty) {}

例子

//查询在欧洲人口超过100000的城市
QueryBuilder qb = cityDao.queryBuilder().where(Properties.Population.ge(1000000));
Join country = qb.join(Properties.CountryId, Country.class);
Join continent = qb.join(country, CountryDao.Properties.ContinentId,
Continent.class, ContinentDao.Properties.Id);
continent.where(ContinentDao.Properties.Name.eq("Europe"));
List bigEuropeanCities = qb.list();

3.5 异步的增删改查

当数据量很大时 ,需要考虑使用异步方式,这样不至于导致线程堵塞等问题。

异步操作相对也比较简单 ,主要使用 有这么几步:

1. 获取 AsyncSession
AsyncSession asyncSession = mDaoSession.startAsyncSession();
2. 设置回调

回调方法是在主线程,查询是在子线程

asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                ...
            }
        });
3. 执行

asyncSession 也有一系列的增删改查

asyncSession.loadAll(object);

下面看一个完成的异步查询的例子

public  void queryAsyncAll(Class object, Query query) {
    AsyncSession asyncSession = mDaoSession.startAsyncSession();
    asyncSession.setListenerMainThread(new AsyncOperationListener() {
        @Override
        public void onAsyncOperationCompleted(AsyncOperation operation) {
            if (operation.isCompleted() && mCallBack != null) {
                List result = (List) operation.getResult();
                mCallBack.onSuccess(result);
            } else if (operation.isFailed() && mCallBack != null) {
                mCallBack.onFailed();
            }
        }
    });
    if (query == null) {
        asyncSession.loadAll(object);
    } else {
        asyncSession.queryList(query);
    }
}

4 封装

4.1 构造单例

下面这部分不难理解,构造 DbUtil 的单例,三个重载函数,可以指定名字,可以设置数据库密码,或者直接使用默认的名字,不加密。

主要是创建 DaoMaster 和 DaoSession 对象,然后使用 DaoSession 对象来获得每个 Entity 对应的 EntityDao 对象,常用的增删改查都是使用 EntityDao 对象来完成的。DaoSession 也具有增删改查功能,而且具有缓存功能,当查询一个对象2次时,取出来的对象是同一个,即使 Entity 的数据有变动,所以这时需要清除一下缓存 DaoSession.clear(),上文提到的异步操作,也是需要 DaoSession 来完成。

private static final String DEFAULT_DATABASE_NAME = "Database.db";
private static final String DEFAULT_DATABASE_PASSWORD = "hahaha";
private DaoSession mDaoSession;
private DaoMaster mDaoMaster;
private AbstractDao mAbstractDao;
private static DbUtil mDbUtils;
private DaoMaster.DevOpenHelper mHelper;
private DbCallBack mCallBack;
    
private DbUtil(Application application, String dbName, String passWord) {
    if (mHelper == null) {
        mHelper = new DaoMaster.DevOpenHelper(application, dbName);
    }
    if (passWord == null || passWord.isEmpty()) {
        mDaoMaster = new DaoMaster(mHelper.getWritableDb());
    } else {
        mDaoMaster = new DaoMaster(mHelper.getEncryptedReadableDb(passWord));
    }
    mDaoSession = mDaoMaster.newSession();

}

public static DbUtil getInstance(Application application) {
    return getInstance(application, DEFAULT_DATABASE_NAME);
}

public static DbUtil getInstance(Application application, String dbName) {

    return getInstance(application, dbName, "");
}

public static DbUtil getInstance(Application application, String dbName, String passWord) {

    if (mDbUtils == null) {
        synchronized (DbUtil.class) {
            if (mDbUtils == null) {
                mDbUtils = new DbUtil(application, dbName, passWord);
            }
        }
    }

    return mDbUtils;
}

4.2 AbstractDao

这里封装的工具类里面没有使用具体的 EntityDao对象,因为EntityDao对象 是在编译后自动生成的,所以使用基类 AbstractDao,这样就可以不用做类型判断。


    /**
     * 插入一条数据
     *
     * @param dbEntity
     */
    public  void insert(T dbEntity) {
        setCurrentDao(dbEntity.getClass());
        mAbstractDao.insert(dbEntity);
    }
    
    private void setCurrentDao(Class entityClass) {
        if (mHelper == null) {
            throw new NullPointerException("You need to init mHelper first!");
        }
        mAbstractDao = mDaoSession.getDao(entityClass);
    }

4.3 增删改查(主线程)

下面的增删改查方法,是在主线程运行的,在数据量较小时,影响很小,不会造成线程堵塞或者 ANR。

    /**
     * 获取数据库Item的数量
     *
     * @return
     */
    public  Long count(Class entityClaz) {
        setCurrentDao(entityClaz);
        return mAbstractDao.count();
    }

    /**
     * 插入一条数据
     *
     * @param dbEntity
     */
    public  void insert(T dbEntity) {
        setCurrentDao(dbEntity.getClass());
        mAbstractDao.insert(dbEntity);
    }

    /**
     * 插入一条数据
     *
     * @param dbEntity
     */
    public  void insertOrReplace(T dbEntity) {
        setCurrentDao(dbEntity.getClass());
        mAbstractDao.insertOrReplace(dbEntity);
    }

    /**
     * 插入多条数据
     *
     * @param entities
     */
    public  void insertTx(List entities) {

        if (entities == null || entities.size() < 1) {
            return;
        }
        setCurrentDaoOfList(entities);
        mAbstractDao.insertInTx(entities);
    }

    public  void insertOrReplaceInTx(List entities) {
        if (entities == null || entities.size() < 1) {
            return;
        }
        setCurrentDaoOfList(entities);
        mAbstractDao.insertOrReplaceInTx(entities);
    }

    /**
     * 删除单条数据
     *
     * @param entity
     */
    public  void delete(T entity) {
        setCurrentDao(entity.getClass());
        mAbstractDao.delete(entity);
    }

    /**
     * 删除特定ID的数据
     *
     * @param id
     */
    public  void deleteById(Class entityClaz, long id) {
        setCurrentDao(entityClaz);
        mAbstractDao.deleteByKey(id);
    }

    /**
     * 删除多条数据
     *
     * @param entities
     */
    public  void deleteList(List entities) {
        setCurrentDaoOfList(entities);
        mAbstractDao.deleteInTx(entities);
    }

    /**
     * 全部删除
     */
    public void deleteAll(Class claz) {
        setCurrentDao(claz);
        mAbstractDao.deleteAll();
    }

    /**
     * 更新单条数据
     *
     * @param entity
     */
    public  void updateData(final T entity) {
        setCurrentDao(entity.getClass());
        mAbstractDao.update(entity);
    }
    
    /**
     * 更新多条数据
     *
     * @param entities
     */
    public  void updateListData(Collection entities) {
        setCurrentDaoOfList(entities);
        mAbstractDao.updateInTx(entities);
    }

    /**
     * 查询特定ID的数据
     *
     * @param id
     * @return
     */
    public  T queryById(Class claz,long id) {
        setCurrentDao(claz);
        return (T) mAbstractDao.load(id);
    }

    /**
     * 查询全部数据
     *
     * @return
     */
    public  List queryAll(Class claz) {
        setCurrentDao(claz);
        return mAbstractDao.loadAll();
    }
    
    /**
     *  原生查询
     * @param claz
     * @param whereString
     * @param params
     * @param 
     * @return
     */
    public  List queryRaw(Class claz,String whereString, String[] params) {
        setCurrentDao(claz);
        return mAbstractDao.queryRaw(whereString, params);
    }

4.4 异步查询

异步操作需要设置回调,回调中可以将结果返回来,比如查询时,拿到查询的结果。

/**
     * 异步操作的回调设置
     * @param callBack
     * @param 
     * @return
     */
    public  DbUtil setDbCallBack(DbCallBack callBack) {
        mCallBack = callBack;
        return this;
    }
    /**
     * 条件查询数据
     *
     * @param cls
     * @return
     */
    public  void queryAsync(Class cls, WhereCondition whereCondition) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    List list = new ArrayList<>();
                    list.add(((T) operation.getResult()));
                    mCallBack.onSuccess(list);
                } else if (operation.isFailed()) {
                    mCallBack.onFailed();
                }
            }
        });
        Query query = mDaoSession.queryBuilder(cls).where(whereCondition).build();
        asyncSession.queryUnique(query);
    }

    /**
     * @param claz
     * @param query 可使用 getQuery 方法获取 Query
     * @param 
     */
    public  void queryAsyncAll(Class claz, Query query) {
        setCurrentDao(claz);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompleted() && mCallBack != null) {
                    List result = (List) operation.getResult();
                    mCallBack.onSuccess(result);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onFailed();
                }
            }
        });
        if (query == null) {
            asyncSession.loadAll(claz);
        } else {
            asyncSession.queryList(query);
        }
    }

    /**
     * 删除
     */
    public  void deleteAsyncSingle(T entry) {
        setCurrentDao(entry.getClass());
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.delete(entry);
    }

    /**
     * 批量删除
     */
    public  void deleteAsyncBatch(Class cls, final List list) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.deleteInTx(cls, list);
    }


    /**
     * 根据Id批量删除
     */
    public void deleteByIdBatch(Class claz,List longList) {
        setCurrentDao(claz);
        mAbstractDao.deleteByKeyInTx(longList);
    }

    /**
     * 删除所有数据
     */
    public  void deleteAsyncAll(Class cls) {
        setCurrentDao(cls);
        final AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.deleteAll(cls);
    }

    /**
     * 插入一条数据
     */
    public  void insertAsyncSingle(final T entity) {
        setCurrentDao(entity.getClass());
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.runInTx(new Runnable() {
            @Override
            public void run() {
                mDaoSession.insert(entity);
            }
        });
    }

    /**
     * 批量插入
     */
    public  void insertAsyncBatch(final Class cls, final List userList) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.runInTx(new Runnable() {
            @Override
            public void run() {
                for (T object : userList) {
                    mDaoSession.insertOrReplace(object);
                }
            }
        });
    }

    /**
     * 更新一个数据
     */
    public  void updateAsyncSingle(Class cls, T entry) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.update(entry);
    }

    /**
     * 批量更新数据
     */
    public  void updateAsyncBatch(final Class cls, final List tList) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.updateInTx(cls, tList);
    }

上面的方法异步操作没什么可说的,只是看到异步查询的方法中有些参数是 WhereCondition ,有些是 Query。上面提到过 mDaoSession.queryBuilder(claz); 来获取 QueryBuilder,通过 QueryBuilder 再获取 Query。WhereCondition 是查询条件,下面看这样一个使用,你就明白了。

// 把 WhereCondition 附加到 QueryBuilder 上,作为 where 的查询条件设置,最终得到 Query
Query query = mDaoSession.queryBuilder(cls).where(whereCondition).build();

这里重点强调一下,WhereCondition,QueryBuilder,Query 都是 greenDAO 中的类,我们在依赖时有两种方式:
(Android Studio 3.0 以后用法)

  • api
  • implementation
implementation 只能在内部使用此模块,比如一个 libiary 中使用 implementation 依赖了 greenDAO,然后主项目依赖了 libiary,那么,我的主项目就无法访问 greenDAO 中的方法。这样的好处是编译速度会加快,推荐使用 implementation 的方式去依赖,如果你需要提供给外部访问,那么就使用 api 依赖即可。

所以:

(1)如果使用这个工具类时,放在你的主工程下,直接使用 WhereCondition,QueryBuilder,Query 这个几个类是没有问题的。

(2)如果你是将该工具类放在 libiary 中,采用 api 方式依赖,同样也没有问题,直接使用这几个类的方法,因为能够引入这几个类。

(3)关键是这点,将该工具类放在 libiary 中,采用 implementation 方式依赖,这时,你的主工程中将看不到 WhereCondition,QueryBuilder,Query 这个几个类,这时候该怎么办呢?这一点目前么有好的办法,想把 WhereCondition,QueryBuilder,Query再封装一层,有些麻烦,干脆还是采用 (2)中的方式来得简单。

5. greenDAO 工具类封装

5.1 设置

对于 Entity 可以放在 数据库模块中,同时将生成的 DAO 也放在该模块下, 这样能够减少主模块中类的数量,如果有多个模块引用数据库模块,Entity 可以增加包来区分属于不同的模块。以下是数据模块目录结构的示例(Entity 未细分包)

gradle设置DAO生成的路径,以及应用数据的方式,采用 api 方式

5.2 数据路工具类

上面已经提到增删改查的封装,下面给出完整的代码。
工具类代码

    public class DbUtil {

    private static final String DEFAULT_DATABASE_NAME = "Database.db";
    private static final String DEFAULT_DATABASE_PASSWORD = "hahaha";
    private DaoSession mDaoSession;
    private DaoMaster mDaoMaster;
    private AbstractDao mAbstractDao;
    private static DbUtil mDbUtils;
    private DaoMaster.DevOpenHelper mHelper;
    private DbCallBack mCallBack;

    private DbUtil(Application application, String dbName, String passWord) {
        if (mHelper == null) {
            mHelper = new DaoMaster.DevOpenHelper(application, dbName);
        }
        if (passWord == null || passWord.isEmpty()) {
            mDaoMaster = new DaoMaster(mHelper.getWritableDb());
        } else {
            mDaoMaster = new DaoMaster(mHelper.getEncryptedReadableDb(passWord));
        }
        mDaoSession = mDaoMaster.newSession();

    }

    public static DbUtil getInstance(Application application) {
        return getInstance(application, DEFAULT_DATABASE_NAME);
    }

    public static DbUtil getInstance(Application application, String dbName) {

        return getInstance(application, dbName, "");
    }

    public static DbUtil getInstance(Application application, String dbName, String passWord) {

        if (mDbUtils == null) {
            synchronized (DbUtil.class) {
                if (mDbUtils == null) {
                    mDbUtils = new DbUtil(application, dbName, passWord);
                }
            }
        }

        return mDbUtils;
    }

    public  Query getQuery(Class claz){
        return getQueryBuilder(claz).build();
    }

    public  QueryBuilder getQueryBuilder(Class claz){
        return mDaoSession.queryBuilder(claz);
    }
    /**
     * 获取数据库Item的数量
     *
     * @return
     */
    public  Long count(Class entityClaz) {
        setCurrentDao(entityClaz);
        return mAbstractDao.count();
    }

    /**
     * 插入一条数据
     *
     * @param dbEntity
     */
    public  void insert(T dbEntity) {
        setCurrentDao(dbEntity.getClass());
        mAbstractDao.insert(dbEntity);
    }

    /**
     * 插入一条数据
     *
     * @param dbEntity
     */
    public  void insertOrReplace(T dbEntity) {
        setCurrentDao(dbEntity.getClass());
        mAbstractDao.insertOrReplace(dbEntity);
    }

    /**
     * 插入多条数据
     *
     * @param entities
     */
    public  void insertTx(List entities) {

        if (entities == null || entities.size() < 1) {
            return;
        }
        setCurrentDaoOfList(entities);
        mAbstractDao.insertInTx(entities);
    }

    public  void insertOrReplaceInTx(List entities) {
        if (entities == null || entities.size() < 1) {
            return;
        }
        setCurrentDaoOfList(entities);
        mAbstractDao.insertOrReplaceInTx(entities);
    }

    /**
     * 删除单条数据
     *
     * @param entity
     */
    public  void delete(T entity) {
        setCurrentDao(entity.getClass());
        mAbstractDao.delete(entity);
    }

    /**
     * 删除特定ID的数据
     *
     * @param id
     */
    public  void deleteById(Class entityClaz, long id) {
        setCurrentDao(entityClaz);
        mAbstractDao.deleteByKey(id);
    }

    /**
     * 删除多条数据
     *
     * @param entities
     */
    public  void deleteList(List entities) {
        setCurrentDaoOfList(entities);
        mAbstractDao.deleteInTx(entities);
    }

    /**
     * 全部删除
     */
    public  void deleteAll(Class claz) {
        setCurrentDao(claz);
        mAbstractDao.deleteAll();
    }

    /**
     * 更新单条数据
     *
     * @param entity
     */
    public  void updateData(final T entity) {
        setCurrentDao(entity.getClass());
        mAbstractDao.update(entity);
    }

    /**
     * 更新多条数据
     *
     * @param entities
     */
    public  void updateListData(Collection entities) {
        setCurrentDaoOfList(entities);
        mAbstractDao.updateInTx(entities);
    }

    /**
     * 查询特定ID的数据
     *
     * @param id
     * @return
     */
    public  T queryById(Class claz, long id) {
        setCurrentDao(claz);
        return (T) mAbstractDao.load(id);
    }

    /**
     * 查询全部数据
     *
     * @return
     */
    public  List queryAll(Class claz) {
        setCurrentDao(claz);
        return mAbstractDao.loadAll();
    }

    public  List queryAll(Class claz,WhereCondition whereCondition) {
        setCurrentDao(claz);
        return mDaoSession.queryBuilder(claz)
                .where(whereCondition)
                .list();
    }

    public  List queryAll(Class claz,QueryBuilder queryBuilder) {
        setCurrentDao(claz);
        return mDaoSession.queryBuilder(claz).list();
    }

    public  List queryAll(Class claz,Query query) {
        setCurrentDao(claz);
       return query.list();
    }


    /**
     * 原生查询
     *
     * @param claz
     * @param whereString
     * @param params
     * @param 
     * @return
     */
    public  List queryRaw(Class claz, String whereString, String[] params) {
        setCurrentDao(claz);
        return mAbstractDao.queryRaw(whereString, params);
    }

    /**
     * 异步操作的回调设置
     *
     * @param callBack
     * @param 
     * @return
     */
    public  DbUtil setDbCallBack(DbCallBack callBack) {
        mCallBack = callBack;
        return this;
    }

    /**
     * 条件查询数据
     *
     * @param cls
     * @return
     */
    public  void queryAsync(Class cls, WhereCondition whereCondition) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    List list = new ArrayList<>();
                    list.add(((T) operation.getResult()));
                    mCallBack.onSuccess(list);
                } else if (operation.isFailed()) {
                    mCallBack.onFailed();
                }
            }
        });
        Query query = mDaoSession.queryBuilder(cls).where(whereCondition).build();
        asyncSession.queryUnique(query);
    }

    /**
     * 异步条件查询,通过使用 QueryBuilder 构造 Query
     * @param claz
     * @param builder
     * @param 
     */
    public  void queryAsyncAll(Class claz, QueryBuilder builder) {
        setCurrentDao(claz);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompleted() && mCallBack != null) {
                    List result = (List) operation.getResult();
                    mCallBack.onSuccess(result);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onFailed();
                }
            }
        });
        if (builder == null || builder.build() == null) {
            asyncSession.loadAll(claz);
        } else {
            asyncSession.queryList(builder.build());
        }
    }

    /**
     * 删除
     */
    public  void deleteAsyncSingle(T entry) {
        setCurrentDao(entry.getClass());
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.delete(entry);
    }

    /**
     * 批量删除
     */
    public  void deleteAsyncBatch(Class cls, final List list) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.deleteInTx(cls, list);
    }


    /**
     * 根据Id批量删除
     */
    public  void deleteByIdBatch(Class claz, List longList) {
        setCurrentDao(claz);
        mAbstractDao.deleteByKeyInTx(longList);
    }

    /**
     * 删除所有数据
     */
    public  void deleteAsyncAll(Class cls) {
        setCurrentDao(cls);
        final AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.deleteAll(cls);
    }

    /**
     * 插入一条数据
     */
    public  void insertAsyncSingle(final T entity) {
        setCurrentDao(entity.getClass());
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.runInTx(new Runnable() {
            @Override
            public void run() {
                mDaoSession.insert(entity);
            }
        });
    }

    /**
     * 批量插入
     */
    public  void insertAsyncBatch(final Class cls, final List userList) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.runInTx(new Runnable() {
            @Override
            public void run() {
                for (T object : userList) {
                    mDaoSession.insertOrReplace(object);
                }
            }
        });
    }

    /**
     * 更新一个数据
     */
    public  void updateAsyncSingle(Class cls, T entry) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.update(entry);
    }

    /**
     * 批量更新数据
     */
    public  void updateAsyncBatch(final Class cls, final List tList) {
        setCurrentDao(cls);
        AsyncSession asyncSession = mDaoSession.startAsyncSession();
        asyncSession.setListenerMainThread(new AsyncOperationListener() {
            @Override
            public void onAsyncOperationCompleted(AsyncOperation operation) {
                if (operation.isCompletedSucessfully() && mCallBack != null) {
                    mCallBack.onNotification(true);
                } else if (operation.isFailed() && mCallBack != null) {
                    mCallBack.onNotification(false);
                }
            }
        });
        asyncSession.updateInTx(cls, tList);
    }

    /**
     * 关闭DaoSession
     */
    private void closeDaoSession() {
        if (mDaoSession != null) {
            mDaoSession.clear();
            mDaoSession = null;
        }
    }

    /**
     * 关闭Helper
     */
    private void closeHelper() {
        if (mHelper != null) {
            mHelper.close();
            mHelper = null;
        }
    }

    /**
     * 关闭所有的操作
     */
    public void closeConnection() {
        closeDaoSession();
        closeHelper();
    }

    /**
     * 数据库不加密
     *
     * @param entityClass 根据 entityClass 获取相应的 xxDao
     * @return mDbUtils
     */
    @Deprecated
    public DbUtil create(Class entityClass) {

        if (mHelper == null) {
            throw new NullPointerException("You need to init mHelper first!");
        }

        mAbstractDao = mDaoSession.getDao(entityClass);
        return mDbUtils;
    }

    private  void setCurrentDao(Class entityClass) {
        if (mHelper == null) {
            throw new NullPointerException("You need to init mHelper first!");
        }
        mAbstractDao = mDaoSession.getDao(entityClass);
    }

    private  void setCurrentDaoOfList(Collection entities) {
        if (entities != null && entities.size() > 1) {
            Iterator iterator = entities.iterator();
            T next = iterator.next();
            setCurrentDao(next.getClass());
        }
    }
}

回调接口

public interface DbCallBack {

    void onSuccess(List result);
    void onFailed();
    void onNotification(boolean result);
}

5.3 使用示例

下面看一个示例:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private DbUtil dbUtil;
    ...
    
    // 异步查询回调
    DbCallBack studentDbCallBack = new DbCallBack() {
        @Override
        public void onSuccess(List result) {
            if (result.size() > 0) {
                for (Student student1 : result) {
                    Log.e(TAG, "[4] " + student1.toString());
                }
            }
        }

        @Override
        public void onFailed() {

        }

        @Override
        public void onNotification(boolean result) {

        }
    };
    
   @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
            case R.id.delete_btn:
                // 删除
                if (dbUtil.count(Clazz.class) > 0) {
                    dbUtil.deleteAll(Clazz.class);
                }

                break;

            case R.id.insert_btn:

                // 批量插入
                dbUtil.insertOrReplaceInTx(clazzList);
                dbUtil.insertOrReplaceInTx(studentList);
                break;

            case R.id.query_btn:
                // 单条查询
                Clazz cls = dbUtil.queryById(Clazz.class,1);

                // 查询所有的班级
                List clazList = dbUtil.queryAll(Clazz.class);
                for (Clazz clazz : clazList) {
                    Log.e(TAG, "[1] " + clazz.toString());
                }
                // 查询所有学生
                List studentList = dbUtil.queryAll(Student.class);
                for (Student student : studentList) {
                    Log.e(TAG, "[2] " + student.toString());
                }
                
                //条件查询
                final List student = dbUtil.queryRaw(Student.class, "where studentID = ?", new String[]{"12"});
                Log.e(TAG, "[3] " + student.get(0).toString());

                // 异步查询
                DbCallBack studentDbCallBack = new DbCallBack() {
                    @Override
                    public void onSuccess(List result) {
                        if (result.size() > 0) {
                            for (Student student1 : result) {
                                Log.e(TAG, "[4] " + student1.toString());
                            }
                        }
                    }

                    @Override
                    public void onFailed() {

                    }

                    @Override
                    public void onNotification(boolean result) {

                    }
                };

                dbUtil.setDbCallBack(studentDbCallBack)
                        .queryAsync(Student.class, StudentDao.Properties.StudentID.eq(19));

                // 批量异步条件查询
                QueryBuilder builder = dbUtil.getQueryBuilder(Student.class)
                        .where(StudentDao.Properties.StudentID.between(12, 16));

                dbUtil.setDbCallBack(studentDbCallBack)
                        .queryAsyncAll(Student.class, builder);

                // 批量同步条件查询
                QueryBuilder builder1 = dbUtil.getQueryBuilder(Student.class)
                        .limit(3)
                        .distinct()
                        .offset(2);

                List list = dbUtil.queryAll(Student.class, builder1);
                for (Student student1 : list) {
                    Log.e(TAG, "[4] " + student1.toString());
                }

                break;

            case R.id.join_btn:

                // 多表查询
                QueryBuilder builder2 = dbUtil.getQueryBuilder(Student.class);
                builder2.join(StudentDao.Properties.ClazID, Clazz.class)
                        .where(ClazzDao.Properties.Id.eq(1));
                List studentList1 = builder2.list();
                for (Student student2 : studentList1) {
                    Log.e(TAG, "" + student2.toString());
                }
                break;

        }

注意

对于 WhereCondition,一般使用 DAO 来构造

    StudentDao.Properties.StudentID.eq(19)

5 总结

greenDAO 使用起来稍微有一点麻烦,但是效率高,这个我也是看其他文章这么写的,没有亲自试过,有兴趣的小伙伴可以尝试测试测试。至于它的封装,目前我也没有想到更好的方式,如果有更好的方式可以拿出来分享,或者对的上面的封装有改进的地方,也可以提出优化的意见!

代码地址

参考:

greenDAO 官网

greendao 3.0集成和使用封装

GreenDao3.0 高级用法

数据库调试工具

你可能感兴趣的:(数据库学习之 GreenDAO 实战)