记录自己的学习,以下为当前的翻译水平翻译的原文。
Queries
Queries返回满足某些特定标准的实体。在GreenDAO你可以用原始的SQL语句,也可以用QueryBuilder更容易做到。
同样,queries支持延迟加载结果,在加载一些大的数据需要保存到内存和不影响性能。
QueryBuilder
SQL可能比较难写,而且只在运行时才能发现错误。QueryBuilder类让你不用SQL构建自定义查询,并帮你在编译时就发现错误。
简单的条件例子:查询所有以Joe为firstname的user,并按last name排序,具体代码如下:
List joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"))
.orderAsc(Properties.LastName)
.list();
嵌套条件的例子:查询first name是Joe,并且出生在1970年10月或更晚的user。
我们可以将user生日的年月日作为特殊的查询条件,以一个更正式的方式表达条件:
First name is "Joe" AND (year ofbirth is greater than 1970 OR (year of birth is 1970 AND month of birth isequal to or greater than 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();
Limit, Offset, and Pagination
有些时候你可能只需要一个查询的子集,例如前10条查询结果展示在UI中。当你有大量的查询结果并且你不能用"where"语句限制查询结果时这是特别有帮助的。QueryBuilder有方法去定义limit和offset:
limit(int):限制查询结果返回的数量。
offset(int):用limit和offset组合使用限制查询结果。第一个limit的结果被跳过,并且总的结果数量被limit限制。你不能单独使用offset
Custom Types as Parameters
通常,GreenDAO在查询时透明的映射结果的类型。例如boolean被映射成INTEGER(值为0或1),Date被映射成(long)INTEGER值。
Custom Type是一个例外:当你构建一个查询语句时,你使用的数据库值的类型。例如,如果你有一个枚举类型用转换器时被映射成一个int类型,你应该在查询中使用int值。
Query and LazyList
用Query类表示的查询可以被执行多次。当你用QueryBuilder中的任何方法去获取结果(例如list),QueryBuilder内部的使用Query类。如果你想运行相同的查询多次,你应该在QueryBuilder中用bulid()去创建不执行的查询。
GreenDao支持唯一的结果(结果0或1)或结果列表。如果你期待一个唯一的结果,在Query(或QueryBuilder)中用unique(),当没有匹配的结果时将返回单个值或null。如果你禁止返回null的结果,使用uniqueOrThrow()将会保证返回一个非空的结果(否则它将会抛出一个DaoException的异常)。
如果你期待多个entity作为返回结果,使用以下的方法:
list() :所有的entity将被加载到内存。结果为一个典型的ArrayList,最容易使用。
listLazy() :entity将根据需求被加载进内存。当列表中的元素被第一次访问时,它被加载并缓存以备未来使用。必须被关闭。
listLazyUncached() :一个”虚拟“的entity列表:任何对列表中元素的访问将被从数据库中加载数据。必须被关闭。
listIterator() : 让你循环访问结果通过根据需求加载数据。数据不缓存。必须被关闭。
方法listLazy(),listLazyUncached(),listIterator(),必须使用GreenDAO的LazyList类。根据需求加载数据,需要引用数据库游标,这就是你必须确定关闭延迟加载列表和Iterator(通常在一个try/catch块中)。
一旦所有的元素被访问或遍历,缓存的延迟加载列表从listLazy()和延迟加载iterator从lisIterator()自动关闭游标。然而,如果列表进程过早的结束,你需要调用close()函数。
Executing Queries multiple times
一旦你正在用QueryBuilder构建一个查询,Query object能拒绝执行后来的查询。这将比一直创建新的Query object更高效。如果查询参数不改变,你可以再一次调用list/unique方法。
然而,参数可能改变:调用setParameter()方法为每一次的参数改变。
目前,独立的参数们以从0开始的索引顺序被处理。索引是传递参数到QueryBuilder的顺序。例如:
// fetch users with Joe as a first name born in 1970
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"), Properties.YearOfBirth.eq(1970)
).build();
List joesOf1970 = query.list();
// using the same Query object, we can change the parameters
// to search for Marias born in 1977 later:
query.setParameter(0, "Maria");
query.setParameter(1, 1977);
List mariasOf1977 = query.list();
Executing queries in multiple threads
如果你在多个线程中使用查询,你必须调用forCurrentThread()函数为当前线程得到一个查询实例。查询的实例被绑定到构建查询的线程。
这让你安全的设置参数在QueryObject,其他线程不能干扰。如果其它线程尝试给查询设置参数或者执行查询绑定到另一个线程,将会扔出异常。就像你不需要一个同步的句子。事实上你应该避免锁定,因为这将可能导致死锁,如果当前交易用了相同的Query Object。
每次forCurrentThread()被调用,在查询使用builder被构建时参数被设置初始化。
Raw queries
以防QueryBuilder不提供你所需要的,有两种方法执行原始SQL,同时返回entity对象。第一,首选的方式是使用QueryBuilder和whereCondition.StringCondition。你可以输入任何的SQL片段作为query builder的WHERE字句。
以下代码是一个理论例子,你如何去运行一个子查询(用一个join将会更好的情况):
Query query = userDao.queryBuilder().where(
new StringCondition("_ID IN " +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)")
).build();
第二种方式是使用queryRaw()或者queryRawCreate()方法。他们允许你传递一个原始的SQL字符串附加到SELECT和entity 列之后。这种方式你可以有任何的WHERE和ORDER BY子句。entity table 可以用T作为别名被提到。
以下的例子展示了怎样创建一个查询:通过join检索被称为admin的用户分组(GreenDAO支持joins,这里仅作证明)
Query query = userDao.queryRawCreate(
", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin"
);
Delete queries
执行批量删除需要创建一个QueryBuilder,调用buildDelete()方法,并且执行返回的DeleteQuery。这部分API可能会被更改,增加更方便的功能。批量删除不影响实体的标识范围,你可以复活已经缓存但被删除的实体,可以通过它们的ID访问。
Troubleshooting queries
你可以使用以下语句将sql命令和传递的值打印到日志中,以便查找错误或复制sql语句。
QueryBuilder.LOG_SQL = true;
QueryBuilder.LOG_VALUES = true;