亲测可用,若有疑问请私信
这是一篇关于greenDao的简明使用教程(其实就是官网tutorial的一个大概的翻译)。
一共有四篇,链接如下:
查询
查询接口返回符合指定条件的实体对象集合.你可以使用SQL组织你的查询语句,或者采用更好的方法,使用greenDao的QueryBuilder API.greenDao的查询也支持延迟加载结果,当结果集很大的时候,它会节省内存和提高性能.
1.QueryBuilder
QueryBuilder类让你不需要写SQL来构建查询条件.写SQL大多数人都不喜欢,并且容易出错,因为它需要在运行时才能反馈错误.QueryBuilder容易使用并且不需要写SQL.使用它,相比只想代码不容易产生bug,它的语法在编译时候就会检查完.以greenDao为基础的代码生成的方法,使编译时的检查项能包括每一个属性的引用.
例如:查询以Joe为名,以姓排序的所有用户.
-
List joes = userDao.queryBuilder()
-
.where(Properties.FirstName.eq("Joe"))
-
.orderAsc(Properties.LastName)
-
.list();
嵌套条件的例子:获取出生在1970年10月以后名为Joe的所有用户. 我们将用户生日对应到实体的年、月、日属性.我们使用更正式的形式将查询条件表达为:名是Joe AND(生日的年份大于1970 OR(生日的年是1970 AND 生日的月等于或大于10))
-
QueryBuilder qb = userDao.queryBuilder();
-
qb.where(Properties.FirstName.eq("Joe"),
-
qb.or(Properties.YearOfBirth.gt(1970),
-
qb.and(Properties.YearOfBirth.eq(1970), Properties.MonthOfBirth.ge(10))));
-
List youngJoes = qb.list();
2.Query类和LazyList类
Query类对象代表一个可以被多次执行的查询.当你使用QueryBuilder中的一个方法来获取结果(如一个list()方法),QueryBuilder内部使用Query类.如果你要以相同的条件多次查询,你可以调用QueryBuilder的build()方法来产生一个Query,不需要执行它.
greenDao支持唯一结果(0或1个结果)、和多个结果的查询.如果你期望唯一的结果,调用Query或者QueryBuilder的unique()方法,它会给你唯一的结果或者null(如果没有找到匹配的实体).如果你的情况不允许null作为结果,调用uniqueOrThrow(),它会保证返回非空的实体(如果没有匹配的结果,它会抛出DaoException异常).
如果查询时你期望返回多个结果,你可以调用list...中的一个方法:
:--:|:--:
list()|所有实体加载到内存.结果是一个典型的ArrayList.容易使用
listLazy()|实体根据需要加载到内存.一旦列表中一个元素被使用,这个元素会被加载和缓存起来,给后续重复使用.使用完后需要关闭 listLazyUncached()|一个虚拟的实体列表:任何请求列表中的元素将会触发从数据库加载数据.使用后必须关闭 listIterator()|让你使用迭代器来遍历结果集,它根据需要加载数据(延迟加载).数据没有缓存,使用后必须关闭
listLazy、listLazyUncached和listIterator 使用了greenDao的LazyList类.为了使用时才加载数据,它保存了数据库游标的引用.这也是使用后必须调用关闭方法的原因(一般在try/finally代码块中关闭).一旦所有的元素被访问或遍历到,listLazy()返回有缓存、延迟加载列表和listIterator()返回的延迟加载迭代器会自动关闭数据库游标.如果数据的访问过早的结束了(没有遍历完全),那么关闭数据库游标是你要做的的工作.
3.使用Queries进行多次查询
一旦你使用QueryBuilder构造了一个query,这个query对象后续可以重复使用,来执行查询.这比总是创建新的Query对象要更有效.如果查询条件没有变,你只需要再次调用其中一个list/unique方法.如果参数有改变,你必须对改变的参数调用setParameter方法.目前,各个参数以0开始的索引来区分.对应你传入参数到QueryBuilder的索引.
下面的例子使用Query对象来查询"名"为Joe,出生在1970年的用于:
-
Query query = userDao.queryBuilder().where(
-
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
-
.build();
-
List joesOf1970 = query.list();
使用这个Query对象,我们查找名为Marias,出生在1977年的用户:
-
query.setParameter(0, "Maria");
-
query.setParameter(1, 1977);
-
List mariasOf1977 = query.list();
4.在多线程中执行查询
如果你想在多线程中使用查询,你必须对query对象调用forCurrentThread()方法来获取一个当前线程的Query实例.从greenDao1.3以后,Query的实例对象绑定到构建query的线程中.这样,你可以安全的对Query对象设置参数而不受其他线程的干扰.如果其他线程试图对query对象设置参数或者执行绑定在其他线程的查询,greenDao会抛出异常.这样,你就不需要使用同步语句.事实上,我们应该避免使用锁,因为如果并发事务使用同一个Query对象,它会导致死锁.
为了完全避免潜在的死锁,greenDao1.3引入了forCurrentThread()函数.它会返回本线程的Query实例,它在当前线程可以安全的使用.每次调用forCurrentThread(),传入的参数和使用QueryBuilder构造Query的参数一致.
5.原始查询
获取数据,有两种方法来执行原始的SQL.比较好的方法是使用QueryBuilder和WhereCondition.StringCondition. 使用它,你可以向QueryBuilder传入任何的SQL WHERE子句片段.下面的代码是一个笨拙的方法,它让你使用一个select子句来起到join的效果
-
Query query = userDao.queryBuilder().where(
-
new StringCondition("_ID IN " +
-
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();
碰到QueryBuilder没有提供你需要的特性时(例如上面的join关键字),你可以回到原始的查询语句或者原始查询语句的构造方法.他们允许传入原始SQL字符串,追加到SELECT + 实体列名后面.通过这种方法,你可以拼好任意WHERE和ORDER BY子句,来查询数据库中的对象.实体表名用别名"T"来称呼:
下面的例子展示了如何使用join创建query对象,它查找组名为"admin"的用户群.
-
Query query = userDao.queryRawCreate(
-
", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
注意:你可以使用生成的常量来指向表和列名.这是推荐的做法,它可以避免错别字,因为编译器会检查名字.在实体对应的Dao类中,你会找到TABLENAME,它持有数据库表的名字.Dao类中还有一个Properties内部类 ,包含所有的属性常量(对应数据库列名).
6.删除查询
批量删除会删除符合条件的实体.想要行批量删除,需要创建一个QueryBuilder,调用它的buildDelete方法,执行返回的DeleteQuery.这部分的api将来可以会修改,例如,会添加便利的方法.记住,批量删除目前不会影响identity scope中的实体,例如实体已经有缓存并且是调用传入ID来获取的函数,你可以"复活"他们.如果这里给你的情况带来一些问题,你可以考虑清除identity scope.
7.查找查询中的问题
你的查询没有返回你期望的值?这里有2个静态的标识,一个是将sql语句打印出来,一个是将传入QueryBuilder的参数打印出来:
-
QueryBuilder.LOG_SQL = true;
-
QueryBuilder.LOG_VALUES = true;
这些日志会记录生成的sql命令和调用build()方法传入的参数.这样你可以对比他们是不是你预期的.这也帮助你们拷贝sql语句到其他数据库浏览工具,并执行他们获取结果。