greenDAO系列5--查询

本文转自:http://my.oschina.net/u/1052509/blog/312608


摘要  查询就是返回符合一定条件的实体。可使用原始的SQL语句执行查询;或是更好的方式,使用greenDAO中QueryBuilder的API。查询支持懒加载,当操作较大的结果集时,便可节约内存、提高性能。

    查询就是返回符合一定条件的实体。可使用原始的SQL语句执行查询;或是更好的方式,使用greenDAO中QueryBuilder的API。查询支持懒加载,当操作较大的结果集时,便可节约内存、提高性能。


QueryBuilder

    QueryBuilder类可构建自定义查询,而无需接触SQL语句。编写SQL语句不是每个人都喜欢并且它容易导致在运行时才发现的错误。而QueryBuilder简单易用,将你从编写SQL语句中拯救出来。同时它不易在查询代码中出现bug,因为在编译时会进行语法检测。编译时的检查包括对属性的引用,这样greenDAO就可以在底层通过代码生成的方式组成SQL语句。

举例:查询所有名为“Joe”的用户,且按姓排序。

?
1
2
3
4
List joes = userDao.queryBuilder()
.where(Properties.FirstName.eq( "Joe" ))
.orderAsc(Properties.LastName)
.list();

嵌套条件的例子:获取名为“Joe”出生在1970年10月份或1970年之后的用户。假如用户的生日分成年月日三个字段,这样便可换一种方式来表示上面的查询:名字是“Joe” AND (生日年份大于1970 OR(生日年份是1970  AND 月份大于等于10))。

?
1
2
3
4
5
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();


Query和LazyList

    Query类代表着一个查询,可被执行多次。但使用QueryBuilder的方法之一(如list())获取一个结果时,QueryBuilder内部就是使用Query类。如果要多次执行相同的请求,可调用QueryBulder的build()方法创建一个查询而非执行它。

    greenDAO同时支持获取单个结果(0或者1个结果)和结果列表。若期待获取一个结果可以调用Query(或QueryBulder)的unique(),这将返回一个结果或匹配不到返回null。若不允许返回nul,可调用uniqueOrThrow(),它将保证返回一个非null实体(否则会抛出一个DaoException)。

    若期待返回多个结果,可以调用下面的list...方法:

list() 所有实体载入内存,以ArrayList形式返回,使用最简单。
listLazy() 实体按需加载到内存。当列表中的其中一个元素第一次被访问,它会被加载并缓存备将来使用。使用完必须关闭。
listLazyUncached() 一个“虚拟”的实体列表:任何访问列表中的元素都会从数据库中读取。使用完必须关闭。
listIterator 可迭代访问结果集,按需加载数据,数据不缓存。使用完必须关闭。

    方法listLazy,listLazyUncached和 listIterator需使用greenDAO的LazyList类。LazyList持有一个数据库游标,可按需加载数据。这也是为什么必须确保关闭懒加载列表和迭代器(通常使用try/finally包裹)。listLazy()的懒加载列表和listIterator()懒加载迭代器,在所有元素被访为或遍历后自动关闭游标。但是,还是必须调用close()方法,防止list的执行过早结束。


多次执行查询

    通过QueryBuilder创建一个Query,Query对象可以在一次查询结束后重新使用。相比创建新的Query对象,这样更加高效。如果查询参数没有改变,可再次调用list/unique方法。如果参数改变,则必须调用setParameter方法修改相应的参数。参数的索引地址从0开始。而索引为参数添加到QueryBuilder的顺序。

    下面的例子使用一个查询对象,获取以“Joe”为名,出生于1970年的用户:

?
1
2
3
4
Query query = userDao.queryBuilder().where(
Properties.FirstName.eq( "Joe" ), Properties.YearOfBirth.eq( 1970 ))
.build();
List joesOf1970 = query.list();

    使用该查询对象,可搜索“Marias”生于1977年:

?
1
2
3
query.setParameter( 0 "Maria" );
query.setParameter( 1 1977 );
List mariasOf1977 = query.list();


多线程执行查询

    多线程中使用查询,必须调用Query的forCurrentThread()获取当前线程的查询实例。从greenDAO1.3开始,Query对象实例绑定到创建它的线程。这样便可安全的设置Query对象的参数,不受其他线程影响。如果其他线程试图设置参数或执行查询,将抛出异常,这样便无需使用同步语句。实际上我们应该避免加锁,因为在并发处理使用了相同的查询对象,容易导致死锁。为完全避免潜在的死锁,greenDAO1.3引入方法forCurentThread(),返回一个本地线程的Query对象,可以被当前线程安全使用。每次forCurrentThread()方法被调用,所有参数将被设置成该查询被其builder创建时的参数。


原始查询

    有两种方法执行原始SQL语句,获取实体结果集。最好的方式是使用QueryBuilder和WhereCondition.StringCondition。可传入任何SQL片段到WHERE字句。如下:

?
1
2
3
Query query = userDao.queryBuilder().where(
new  StringCondition( "_ID IN "  +
"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)" ).build();

    当QueryBuilder的功能未能符合需求时,可使用queryRaw或queryRawCreate方法。你可传入一个原始语句,它会被添加到SELECT和实体字段后。用这种方式可以编写任何WHERE和ORDER BY字句去查询需要的实体集。实体表可以使用别名“T”来引用。

下面的例子使用联合查询检索所在组为“admin”的所有用。

?
1
2
Query query = userDao.queryRawCreate(
   ", GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID" "admin" );

    注意:可用生成的常量表示表名和字段名。这是推荐的做法,避免编写错误。在一个实体的DAO中,TABLENAME表示数据库的表名,其内部类Properties则有所有属性的常量。


删除实体

//TODO


检测查询

    如果查询结果没有返回你期待的,有两个静态标识可开启QueryBuilder的SQL和参数的日志输出:

?
1
2
QueryBuilder.LOG_SQL =  true ;
QueryBuilder.LOG_VALUES =  true ;

    这样会输出SQL命令和调用相关build方法时传入的参数。


猜你喜欢

转载自blog.csdn.net/wurensen/article/details/47905519