学习GreenDAO的QueryBuilder的使用

时间:2021-12-19 22:39:16

记录自己的学习,以下为当前的翻译水平翻译的原文。学习GreenDAO的QueryBuilder的使用



Queries

Queries返回满足某些特定标准的实体。在GreenDAO你可以用原始的SQL语句,也可以用QueryBuilder更容易做到。

同样,queries支持延迟加载结果,在加载一些大的数据需要保存到内存和不影响性能。

QueryBuilder

SQL可能比较难写,而且只在运行时才能发现错误。QueryBuilder类让你不用SQL构建自定义查询,并帮你在编译时就发现错误。

简单的条件例子:查询所有以Joefirstnameuser,并按last name排序,具体代码如下:


List joes = userDao.queryBuilder()
 .where(Properties.FirstName.eq("Joe"))
 .orderAsc(Properties.LastName)
 .list();

嵌套条件的例子:查询first nameJoe,并且出生在197010月或更晚的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;

原文地址点击打开