前言
這一部分繼續Android數據庫ORMlite框架翻譯系列(第二章:part 1)部分。這章的內容的確不少,所以這次仍然沒有翻譯完。需要快速上手的話你最好看看原文檔。
-------------------------------------------------------------------------------------
2.7 表和Schema創建
有幾個ORMLite提供的工具,可以幫助你為存入數據庫的類創建表和schema。
2.7.1 TableUtils類
TableUtils類提供了一些靜態方法用以輔助創建和刪除表,同樣也提供了schema申明。(下面例舉出靜態方法名,詳細說明參見官網)
| 靜態方法原型 |
| createTable(ConnectionSource, Class) |
| createTableIfNotExists(ConnectionSource, Class) |
| createTable(ConnectionSource, DatabaseTableConfig) |
| createTableIfNotExists(ConnectionSource, DatabaseTableConfig) |
| dropTable(ConnectionSource, Class, boolean ignoreErrors) |
| dropTable(ConnectionSource, DatabaseTableConfig, boolean ignoreErrors) |
| getCreateTableStatements(ConnectionSource, Class) |
| getCreateTableStatements(ConnectionSource, DatabaseTableConfig) |
| clearTable(ConnectionSource, Class) |
| clearTable(ConnectionSource, DatabaseTableConfig) |
2.7.2 TableCreator類
TableCreator這個類雖然是為使用Spring框架設計的,但是在其他的配置方面是很有用的。它配置ConnectionSource和被程序使用的DAO列表。
如果系統屬性ormlite.auto.create.tables設置成true值,他會自動創建和這些DAO相關的表。如果系統屬性ormlite.auto.drop.tables設置成true值,它也會自動刪除創建的表。這在測試的時候特別有用:你開始使用取得最新schema的測試數據庫,但是實際生產過程中你需要手動改變一個具體的schame。你可以在你運行測試腳本的時候設置系統屬性,但是在運行實際腳本時要關閉它。
List<Dao<?, ?>> daoList = new ArrayList<Dao<?, ?>>(); daoList.add(accountDao); ... TableCreator creator = new TableCreator(connectionSource, daoList); // create the tables if the right system property is set creator.maybeCreateTables(); ... // later, we may want to drop the tables that were created creator.maybeDropTables();
2.8 唯一標識符字段
數據庫中的記錄通過定義為唯一的特殊字段成為唯一標識。記錄不是必須有唯一標識字段當時很多DAO操作(更新、刪除、刷新)都需要一個唯一標識字段。這個標識要么用戶提供要么數據庫自動生成。標識字段有表中唯一的值並且如果你用DAO根據id查詢、刪除、刷新或者更新指定行的時候他們必須存在。為了配置一個成員變量作為標識成員,你應該使用下面三個設置之一(而且必須使用一個):@DatabaseField: id, generatedId, generatedIdSequence 。
2.8.1 成員變量使用id
用我們的Account類的示例,字符串name變量被標記有id = true 。這意味着name變量是這個對象的標識字段。每個account存入數據庫都必須有一個唯一的name變量值,比如你不能有兩行的name都是“John Smith”。
public class Account { @DatabaseField(id = true) private String name; ... }
當你使用DAO利用具體的name值查詢時,你將使用標識成員定位數據庫中
的Account對象。
Account account = accountDao.queryForId("John Smith");
if (account == null) {
// the name "John Smith" does not match any rows
}
注意:如果你需要改變對象id字段的值,那么你必須使用Dao.updateId()方法,它獲得當前對象的id舊值和新值。
2.8.2 成員變量使用generatedId
你可以配置一個long或integer的變量作為生成的標識字段。每條記錄的id號都是數據庫自動生成的。
public class Order { @DatabaseField(generatedId = true) private int id; ... }
傳遞一個Order對象去創建和存儲到數據庫時,數據庫返回一個生成的id值並且ORMLite設置給對象。在大部分數據庫類型中向表中插入一條新記錄時生成的值從1開始,每次增長1。
// build our order object without an id Order order = new Order("Jim Sanders", 12.34); ... orderDao.create(order); System.out.println("Order id " + order.getId() + " was persisted to the database"); // query for the order with an id of 1372 order = orderDao.queryForId(1372); if (order == null) { // none of the order rows have an id of 1372 }
在上面的代碼示例中,一個order構造用name和amount兩個屬性。當把它傳給DAO'的create方法時,id變量沒有設置。它保存到數據庫之后,ORMLite會把生成的id設置給id變量並且getId()方法在create方法返回后被order調用是有有效的。
注意:其他特殊變量類型也是可以生成的,比如UUID。你可以使用allowGeneratedIdInsert變量進行設置,允許向表中插入擁有已經設置過或沒有設置過id的對象。根據數據庫類型,你可能不能改變自動生成id字段的值。
2.8.3 成員變量使用generatedIdSequence
一些數據庫使用一種被稱為序列號生成器的東西來提供生成id的值。如果你把generatedId = true用在這些數據庫上,序列名將會被ORMLite自動生成。如果這樣,你需要設置序列名來匹配已經存在的schema,你可以使用generatedIdSequence序列名的值。
public class Order { @DatabaseField(generatedIdSequence = "order_id_seq") private int id; ... }
在上面的示例中,雖然id值再次自動生成,但是仍然使用序列名:order_id_seq 。如果你使用的數據庫不支持序列,那么這將會拋出一個異常。
注意:根據數據庫類型,你不能改變自動生成id字段的值。
2.9 DAO 的使用
下面通過使用DAO方法簡單完成數據庫操作:
①創建並且持久化對象到數據庫。
插入一條和對象相關的記錄到數據庫中。
Account account = new Account(); account.name = "Jim Coakley"; accountDao.create(account);
②查詢它的id字段
如果對象有個id成員變量通過注解定義的,我們可以通過它的id在數據庫中查找一個對象。
Account account = accountDao.queryForId(name); if (account == null) { account not found handling ... }
③更新與對象相關的數據庫記錄
如果你在內存中改變一個對象的成員變量,你必須調用update把它持久化到數據庫。這需要一個id字段。
account.password = "_secret";
accountDao.update(account);
④當數據庫有改變,刷新對象
如果一些與內存中對象相關的數據庫實體發生了改變,你就需要刷新來得到最新的存儲對象。這需要一個id字段。
accountDao.refresh(account);
⑤從數據庫中刪除數據
從數據庫刪除與對象關聯的記錄。一旦對象從數據庫刪除,你可以繼續使用內存中的對象但是任何的更新或者刷新都很可能失敗。這需要一個id字段。
accountDao.delete(account);
⑥遍歷表中所有記錄
DAO也有迭代器,所以你可以簡單的執行數據庫中所有的記錄。
// page through all of the accounts in the database for (Account account : accountDao) { System.out.println(account.getName()); }
注意:你必須遍歷迭代器所有的條目來關閉底層的SQL對象。如果你沒有通過循環走所有的途徑,那么ORMLite不知道關閉底層對象,並且一個到數據庫的連接可能泄露,如果更遲一些垃圾回收器才獲得它,那么它將被迫關閉,這會在你的代碼中產出漏洞。使用下面的try ... finally模板包住迭代器。
例如,下面是一個不好的循環模板。
for (Account account : accountDao) { if (account.getName().equals("Bob Smith")) { // you can't return, break, or throw from here return account; } }
如果一個異常仍出循環這種bug照樣會發生,所以如果這樣的話循環就不應該被使用。這也是一個用遲加載收集的一個案例。
⑦直接使用迭代器
你也可以直接使用迭代器,因為用循環並不是最佳選擇。這種方式允許你使用更好的try ... finally模板。
CloseableIterator<Account> iterator = accountDao.closeableIterator(); try { while (iterator.hasNext()) { Account account = iterator.next(); System.out.println(account.getName()); } } finally { // close it at the end to close underlying SQL statement iterator.close(); }
⑧獲得"wrapped iterable"
你也可以使用"wrapped iterable",它允許你在finally中使用close而一直使用循環。
CloseableWrappedIterable<Account> wrappedIterable = accountDao.getWrappedIterable(); try { for (Account account : wrappedIterable) { ... } } finally { wrappedIterable.close(); }
ps:翻譯中... 本章內容未完。翻譯中如果有不妥之處請讀者提出。
