1. 程式人生 > >ORMLite完全解析(三)官方文件第三章、自定義查詢構造器 Custom Query Builder

ORMLite完全解析(三)官方文件第三章、自定義查詢構造器 Custom Query Builder

          接著上一篇,下面是第三章的翻譯整理,理解錯誤的地方還請批評指正。

 第三章、 自定義查詢構造器

3.1  查詢構造器基礎       下面是使用查詢構造器建立自定義查詢語句的基本步驟。首先,以java常量的形式為屬性設定列名,便於使用它 們進行查詢。       @DatabaseTable(tableName = "accounts")       public class Account {            public static final String PASSWORD_FIELD_NAME = "password";             …
           @DatabaseField(canBeNull = false, columnName = PASSWORD_FIELD_NAME)            private String password;            …        這樣就允許我們使用password屬性構建查詢,而不需要在後面的查詢中重新命名屬性,及時屬性名,和列名一樣也 應該這樣做。         // get our query builder from the DAO        QueryBuilder<Account, String> queryBuilder = accountDao.queryBuilder();
       // the 'password' field must be equal to "qwerty"        queryBuilder.where().eq(Account.PASSWORD_FIELD_NAME, "qwerty");        // prepare our sql statement        PreparedQuery<Account> preparedQuery = queryBuilder.prepare();        // query for all accounts that have "qwerty" as a password
       List<Account> accountList = accountDao.query(preparedQuery);        如上面的程式碼,你可以通過Dao.queryBuilder()方法獲得一個QueryBuilder物件,然後呼叫這個物件的方法,調 用queryBuilder.prepare()函式獲得一個PrepareQuery物件,然後,將這個PrepareQuery方法傳遞到DAO的查詢或者 遍歷方法中。       簡化操作,可以在Where物件中呼叫prepare()方法,如下所示:       // query for all accounts that have that password       List<Account> accountList = accountDao.query(          accountDao.queryBuilder().where()          .eq(Account.PASSWORD_FIELD_NAME, "qwerty")          .prepare());               也可以使用另外一種簡化方法,通過QueryBuilder或者Where物件呼叫query()方法或者iterator()方法。如下:        // query for all accounts that have that password       List<Account> accountList =          accountDao.queryBuilder().where()          .eq(Account.PASSWORD_FIELD_NAME, "qwerty")          .query(); 3.2 構建查詢語句       下面是一些不相同的構建查詢語句的方式。QueryBuilder類已經針對特殊使用和強大的使用者進行了內部封裝。       QueryBuilder<Account, String> queryBuilder =       accountDao.queryBuilder();       // get the WHERE object to build our query       Where<Account, String> where = queryBuilder.where();       // the name field must be equal to "foo"       where.eq(Account.NAME_FIELD_NAME, "foo");       // and       where.and();       // the password field must be equal to "_secret"       where.eq(Account.PASSWORD_FIELD_NAME, "_secret");       PreparedQuery<Account> preparedQuery = queryBuilder.prepare();       上面的語句會生成下面這樣的sql語句       SELECT * FROM account WHERE (name = 'foo' AND password = '_secret')        如果你喜歡使用方法鏈進行操作,則上面的語句也可以這樣寫:        queryBuilder.where()        .eq(Account.NAME_FIELD_NAME, "foo")        .and()        .eq(Account.PASSWORD_FIELD_NAME, "_secret");        如果你喜歡使用括號將比較語句組合在一起,也可以這樣用:        Where<Account, String> where = queryBuilder.where();        where.and(where.eq(Account.NAME_FIELD_NAME, "foo"),        where.eq(Account.PASSWORD_FIELD_NAME, "_secret"));       上面的三種呼叫方式會生成相同的sql語句。對於混合mixANDs和ORs的複雜查詢而言,最後一種格式必須正確組裝 ,如下面這個查詢:       Where<Account, String> where = queryBuilder.where();       where.or(            where.and(                where.eq(Account.NAME_FIELD_NAME, "foo"),                where.eq(Account.PASSWORD_FIELD_NAME, "_secret")            ),            where.and(                where.eq(Account.NAME_FIELD_NAME, "bar"),                where.eq(Account.PASSWORD_FIELD_NAME, "qwerty")            )        );        這個語句會長生下面這樣的sql語句:        SELECT * FROM account        WHERE ((name = 'foo' AND password = '_secret')            OR (name = 'bar' AND password = 'qwerty'))        查詢語句也允許指定需要查詢返回的列,指定ORDER BY和GROUP BY屬性,以及各種各樣的sql特點,比如(LIKE,IN,>,>=,<, <=,<>, IS NULL, DISTINCT,...),具體細節檢視Where Capabilities這節。也可以檢視good SQL reference site中關於QueryBuilder和Where語句的java文件介紹。 3.3  構建更新和刪除語句     DAO物件也可以用於構建自定義的UPDATE和DELETE語句,UPDATE語句用於改變滿足Where條件的資料行中特定的屬 性的值,或者,如果沒有指定where的話,用於更改所有資料行的屬性值。delete語句用於刪除滿足條件的資料行, 如果沒有條件限制,則用於刪除所有資料。     例如,如果你想要更新全部Account中passwords為null的值為“none”,可以使用下面的語句。     UpdateBuilder<Account, String> updateBuilder =     accountDao.updateBuilder();     // update the password to be "none"     updateBuilder.updateColumnValue("password", "none");     // only update the rows where password is null     updateBuilder.where().isNull(Account.PASSWORD_FIELD_NAME);     updateBuilder.update();     通過update語句,也可以指定表示式更新     // update hasDog boolean to true if dogC > 0     updateBuilder.updateColumnExpression("hasDog", "dogC > 0");     為了便於構造你的表示式,可以使用UpdateBuilder的escape方法escapeColumnName和escapeValue值,這個兩個 方法可以攜帶一個String或者StringBuffer,這樣可以避免列名和關鍵字衝突。     如果你想刪除Account表中password為null的一行,可以使用下面的語句完成。     DeleteBuilder<Account, String> deleteBuilder = accountDao.deleteBuilder();     // only delete the rows where password is null     deleteBuilder.where().isNull(Account.PASSWORD_FIELD_NAME);     deleteBuilder.delete(); 3.4  Query功能     下面是關於QueryBuilder各種查詢呼叫的詳情。可以檢視QueryBuilder類的最新JavaDoc文件獲取更多資訊。大 多數的方法都是返回QueryBuilder物件,以便使用方法鏈。     具體細節參考 tutorial of SQL commands.中的詳情。     主要方法包括:     distinct()     groupBy(String columnName)     groupByRaw(String sql)     having(String sql)     join(QueryBuilder joinedQueryBuilder)     leftJoin(QueryBuilder joinedQueryBuilder)     limit(Integer maxRows)     offset(Integer startRow)     orderBy(String columnName, boolean ascending)     orderByRaw(String sql)     prepare()     selectColumns(String... columns)     selectColumns(Iterable<String> columns)     selectRaw(String... columns)     where()     query()     queryForFirst()     queryRawFirst()     iterator()     reset() 3.5  Where功能     下面是關於查詢功能的詳解,更多細節參考tutorial of SQL commands.     主要方法包括:       and()     and(Where<T, ID> first, Where<T, ID> second, Where<T, ID>... others)     and(int numClauses)     between(String columnName, Object low, Object high)     eq(String columnName, Object value)     exists(QueryBuilder<?, ?> subQueryBuilder)     ge(String columnName, Object value)     gt(String columnName, Object value)     idEq(ID id)     idEq(Dao<OD, ?> dataDao, OD data)     in(String columnName, Iterable<?> objects)     in(String columnName, Object... objects)     in(String columnName, QueryBuilder<?, ?> subQueryBuilder)     isNull(String columnName)     isNotNull(String columnName)     le(String columnName, Object value)     lt(String columnName, Object value)     like(String columnName, Object value)     ne(String columnName, Object value)     not()     not(Where<T, ID> comparison)     notIn(String columnName, Iterable<?> objects)     in(String columnName, Object... objects)     notIn(String columnName, QueryBuilder<?, ?> subQueryBuilder)     or()     or(Where<T, ID> first, Where<T, ID> second, Where<T, ID>... others)     or(int numClauses)     raw(String rawStatement)     prepare()     reset()     query()     queryRaw()     queryForFirst()     queryRawFirst()     countOf()     iterator() 3.6  使用select引數     select引數是一種使用在Where操作中的引數,這種引數可以直接指定為引數值(如上例子所示),或者作為一 個select引數物件。select引數可以用於後續設定引數值,他們會產生SQL ‘?’,類似於jdbc的佔位符。     例如:       QueryBuilder<Account, String> queryBuilder = accountDao.queryBuilder();     Where<Account, String> where = queryBuilder.where();     SelectArg selectArg = new SelectArg();     // define our query as 'name = ?'     where.eq(Account.NAME_FIELD_NAME, selectArg);     // prepare it so it is ready for later query or iterator calls     PreparedQuery<Account> preparedQuery = queryBuilder.prepare();     // later we can set the select argument and issue the query     selectArg.setValue("foo");     List<Account> accounts = accountDao.query(preparedQuery);     // then we can set the select argument to another     // value and re-run the query     selectArg.setValue("bar");     accounts = accountDao.query(preparedQuery);     人們通常會試著建立一些具有引數的查詢語句,幷包含一些特定的符號,這些符號能自動生成sql語句,並導致 語法錯誤。在這種情況下可以使用SelectArg。此外,如果你的引數使使用者輸入的,那麼使用SelectArgs可以保護你 的程式避免sql注入問題。其次,特定的資料型別可以使用一種內部的SelectArg物件,因為物件的String值對於資料 庫而言是不可靠的。例如java.util.Date。     注意:SelectArg物件不能再一個物件的多列中使用,如果你想要在另外一列中使用SelectArg,你必須重新例項 化一個新的物件。 3.7  使用列引數     假如你使用QueryBuilder讓一個值和列資料進行比較。那麼可以使用ColumnArg:     例如:           QueryBuilder<Account, String> queryBuilder = accountDao.queryBuilder();     // list all of the accounts that have the same     // name and password field     queryBuilder.where().eq(Account.NAME_FIELD_NAME, new ColumnArg(Account.PASSWORD_FIELD_NAME));     List<Account> results = queryBuilder.query();     ColumnArg也可以攜帶一個表名,這種方式在JION查詢中用於比較一個表中的列和另一個表中的列的資料時比較 有用。詳情檢視Building Join Queries一節。 3.8  構建連線查詢     ORMLite支援基本的JION SQL查詢,更多內容可檢視JOIN documentation.     通過兩個QueryBuilder物件建立一個join查詢,其中一個在DAO中,用於返回你的物件,另一個DAO與第一個DAO 相關聯。其中一個必須是另一個的外部屬性,否則,jion方法會丟擲異常。     例如:假設你想要獲得一個account集合,並且這些account有一個訂單的amount值大於100刀。則可以這樣寫:     QueryBuilder<Order, Integer> orderQb = orderDao.queryBuilder();     orderQb.where().ge("amount", 100.0F);     QueryBuilder<Account, Integer> accountQb = accountDao.queryBuilder();     // join with the order query     List<Account> results = accountQb.join(orderQb).query();     這裡返回了所有的Account記錄,並且,這些物件有一個對應的訂單,這個訂單有一個屬性值大於100.     ORMLite也支援LEFTJOIN的概念,意思是,在上面的例子中,在上面的語句中,沒有訂單的account也會被返回。 但是,ORMLite不支援RIGHT JOIN 和 FULL JOIN的概念。     注意,其他的ORM庫使用JOIN語句從多張表中獲取資料填充外部物件屬性和外部物件集合。ORMLite不支援這種特 性。你只能使用它從一張表中獲得資料。