Query
查询返回的结果的实体符合特定标准。在greenDao中可以使用sql语句,或者更加方便的方式QueryBuilder的api或者是greenDao,greenDao同样支持延迟查询,在查询大量数据的时候可以节约内存,并且提高性能。
QueryBuilder
这个类可以用来自定义查询语句,而不用写SQL语句,写SQL语句不是每个人都喜欢的,同时也容易出错。而且只有运行后才知道写错了sql语句。同时在sql语句中找bug比在语法中找bug要难得多。编译时检查甚至包括引用属性,这是通过greenDAO背后的代码生成器的方法。
Example
查询所有名为joe的通过last name 排序
List joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"))
.orderAsc(Properties.LastName).list()
嵌套查询
查询所有的用户,条件为first name 为Joe,且出生在1970年十月 ,或者更晚。
在数据库中存储用户的生日分为年月日三个字段。根据我们sql知识知道,条件语句为
First name is “Joe” AND (year of birth is greater than 1970 or year of birth is 1970 AND month of birth is greater than octorber)
QueryBuilder的表达方式为:
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)))
Query and LazyList
查询类代表一个可多次执行的查询。当你调用一个QueryBuilder查询到一个结果,queryBuilder内部调用了查询的一个类,如果想要运行同样的查询不止一次,你应该调用build()方法,没有执行它。
greenDao支持0个1个或者多个查询结果,如果期望是一个或者零个查询结果,需要调用unique()方法,在查询结果上。这样子将会返回一个结果,或者没有结果。如果禁止空的查询结果,调用uniqueOrThrow(),这样就能保证返回一个不为空的entity或者抛出一个DaoException。如果期望返回的是一个lis。使用list()方法
list()
所有的entities将会加载到内存,典型的是Arraylist。最简单的
listLazy()
entities将会响应式的加入到内存中,一旦一个元素将要被调用。它将会被加入内存,或者缓存中。一个要记得关闭
listLazyUncached()
一个虚拟的entities的list。任何想要调用list中的元素将会从数据库中加载元素。一定要关闭
listIterator()
遍历结果通过加载数据按需(延迟)。数据没有被缓存。必须关闭。
其中listLazy,listLazyUncached,listIterator是延迟查询,只有再需要调用的时候才加载数据。实际上是引用数据库的游标(cursor)。所以我们用完一定要记得关闭。listLazy()和listIterator(),将会自动关闭游标一旦所有的元素都被遍历或者访问过。如果list处理的结果比较早我们就要手动调用close()方法。
多次执行查询
一旦我们创建了一个查询通过queryBuilder.这个查询对象可以被多次使用。这比经常创建查询要高效多了。如果这个查询没有改变参数,我们只需要再次调用list(),或者unique()方法。如果有参数要改变我们只需为每一个改变的参数调用setParameter()。目前个别参数是由0开始的指引。该指数是基于QueryBuilder订单传递参数。
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970))
.build();
List joesOf1970 = query.list();
修改参数来查询:
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
在不同的线程中查询
如果在不同在线程中进行查询,必须调用forCurrentThread(),来获取一个当前线程的查询实例,
greenDao 1.3之后,查询对象实例是当前线程的实例,这样子就可以安全的设置参数。其他线程就不能接触到这个查询。如果其他线程为这个查询设置参数,或者在其他线程执行查询,一个异常将会抛出,这样子我们就不需要一个synchronized申明。事实上,我们们要避免lock,因为如果并发事物使用的是同一个查询对象将对会导致死锁。
为了避免这些潜在的风险,greenDao 1.3之后引入了方法forCurrentThread()方法。这样将返回一个当前线程的查询实例,这样子就能安全的使用查询。调用了forCurrentThread()方法后只能在它所在的线程中掉用setParameter()
源生查询
有两种方法来执行原始SQL实体,更好的方式是使用QueryBuilder和WhereCondition.通过这种方式你可以传递各种SQL碎片作为where条件语句
Query query = userDao.queryBuilder().where(
new StringConditon("_ID IN" + "(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 00)")).build();
另外一个例子:
Query query = userDao.queryRawCreate(
", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
建议:表名和列名使用常量,这样子就不会拼写出错。
删除查询
批量删除不删除单独的实体,而是删除满足某些条件的所有entities。执行批量删除、创建一个QueryBuilder调用其buildDelete方法,并执行DeleteQuery返回。记住,目前批量删除不影响实体身份范围,例如你可以“复活”删除实体如果他们之前和访问缓存了ID(负载方法)。考虑清理身份范围现在,如果你的用例,可能会导致问题。
所以不建议使用批量删除!!!
故障查询
如果查询没有返回你期望的值,有两个静态标记可以使用
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG.VALUES = true;
这样子就会打印sql语句,和传递的值
-----------------------Sessions--------------------
DaoSession(生产类)是整个greenDao中核心的一个类,作为开始,DaoSession提供了一种途径操作基本的entity,同时提供了Dao,完成一系列的操作。
DaoMaster 和 DaoSession
在快速开始文档部分,我们需要创建一个DaoMaster来获取一个DaoSession
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
noteDao = daoSession.getNoteDao();
数据库连接属于DaoMaster,所以多个会话引用相同的数据库连接,新的session可以被很快的建立起来,然而每个session会占用内存,通常一个session会给entities带来缓存
身份和回话范围“缓存”(Identity scope and session "cache")
假设有两个查询返回相同的数据库对象,我们需要多少个java类来实现它,一个or两个?这个取决是Identity Scope,默认greenDAO(行为是可配置的)是,多个查询返回相同的Java对象。例如,从USER表中加载一个ID为42的用户,greenDao将返回相同的java对象。
这种做法的负面影响是为存在缓存的entities,如果一个entity一直在内存中,这个对象不会用数据库查询到值重新创建,例如,通过ID查询到一个entity对象,这个对象之前已经加载到内存中,greenDao不需要查询数据库,而是立即从session的缓存中返回该对象,这样子会提高1-2个两级的速度