添加ormlite注解
? ? ? ?使用@DatabaseTable和@DatabaseField添加注解瞎访,表示數(shù)據(jù)庫的表和字段祠肥,其實也可以通過Java代碼和Spring XML代碼配置類顿膨。
? ? ? ?@DatabaseTable添加注解的時候可以指定表名钞脂,默認情況下圈驼,和字段名一樣。
高級用戶可能想要在這里添加一個daoClass參數(shù)指定Dao對象的類隐圾,用于操作這個類伍掀。 這個daoClass通過DaoManager使用, 查看DaoManager小節(jié)暇藏。
? ? OrmLite的字段注解參數(shù)包括
? ? ? ? columnName? ? ? ? dataType? ? ? ? defaultValue? ? ? ? width? ? ? ? canBeNull? ? ? ? id? ? ? ? generatedId? ? ? ? generatedIdSequence? ? ? ? foreign? ? ? ? useGetSet? ? ? ? unknownEnumName? ? ? ? throwIfNull? ? ? ? persisted? ? ? ? format? ? ? ? unique? ? ? ? uniqueCombo? ? ? ? index? ? ? ? uniqueIndex? ? ? ? indexName? ? ? ? uniqueIndexName? ? ? ? foreignAutoRefresh? ? ? ? maxForeignAutoRefreshLevel? ? ? ? allowGeneratedIdInsert? ? ? ? columnDefinition? ? ? ? foreignAutoCreate? ? ? ? version? ? ? ? foreignColumnName
2. ?使用標(biāo)準的JPA(javax.persistence?annotations)注解(暫不考慮)
使用@Entity代替@DatabaseTable代替,可以指定一個name參數(shù)值表示表名蜜笤,如果不指定,默認使用類名盐碱。
用@Column,@GeneratedValue,@OneToOne ,@ManyToOne,?@JoinColumn, 和@Version指定字段屬性童漩。
支持的JPA注解包括
@Entity@Column@Id@GeneratedValue@OneToOne or @ManyToOne@JoinColumn@Version2.1.3 ?添加一個無參構(gòu)造函數(shù)通過query獲取對象時,這個無參構(gòu)造函數(shù)用于創(chuàng)建對象狼钮。2.2 ?支持持久化的數(shù)據(jù)類型DatabaseField注解是有一個dataType屬性主守,表明java數(shù)據(jù)類型和sql數(shù)據(jù)類型進行的對應(yīng)數(shù)據(jù)轉(zhuǎn)換,包括如下:
String???????????? (DataType.STRING)
String ????????????(DataType.LONG_STRING)
String???????????? (DataType.STRING_BYTES)
boolean or Boolean???????????????? (DataType.BOOLEAN or ????????????????????????????????????????DataType.BOOLEAN_OBJ)
java.util.Date???????????????? (DataType.DATE)
java.util.Date ????????????(DataType.DATE_LONG)
java.util.Date???????????? (DATE_STRING)
byte or Byte???????????? (DataType.BYTE or ????????????????????????????????DataType.BYTE_OBJ)
byte array ????????????(DataType.BYTE_ARRAY)
char or Character???????????? (DataType.CHAR or ????????????????????????????????????????DataType.CHAR_OBJ)
short or Short???????????? (DataType.SHORT or ????????????????????????????DataType.SHORT_OBJ)
int or Integer???????????????????? (DataType.INTEGER or ????????????????????????????????DataType.INTEGER_OBJ)
long or Long ????????(DataType.LONG or ????????????????????????????????DataType.LONG_OBJ)
float or Float???????????????? (DataType.FLOAT or ????????????????????????????????????DataType.FLOAT_OBJ)
double or Double???????? (DataType.DOUBLE or DataType.DOUBLE_OBJ)
Serializable???????????? (DataType.SERIALIZABLE)
enum or Enum???????? (DataType.ENUM_STRING)
enum or Enum???????????? (DataType.ENUM_INTEGER)
UUID ? ????????????????? (DataType.UUID)
BigInteger???????????? (DataType.BIG_INTEGER)
BigDecimal???????????? (DataType.BIG_DECIMAL)
BigDecimal ????????????(DataType.BIG_DECIMAL_NUMERIC)
DateTime ????????????(DataType.DATE_TIME)
java.sql.Date ????????(DataType.SQL_DATE)
java.sql.Timestamp???????? (DataType.TIME_STAMP)
每個dao類負責(zé)操作一個對應(yīng)的持久化類暖混。DAO類的創(chuàng)建缕贡,包含兩個參數(shù),第一個是持久化類的類名拣播,第二個是該類對應(yīng)的id類型晾咪,可以通過DaoManager的靜態(tài)方法直接創(chuàng)建,如:
Dao accountDao =
DaoManager.createDao(connectionSource, Account.class);
建議創(chuàng)建DAO接口贮配,然后創(chuàng)建實現(xiàn)類谍倦,并且通過daoClass指定
/** Account DAO which has a String id (Account.name) */public interface AccountDao extends Dao {? ? // empty wrapper, you can add additional DAO methods here}
/** JDBC implementation of the AccountDao interface. */
public class AccountDaoImpl extends BaseDaoImpl
? implements AccountDao {
? ? // this constructor must be defined
? ? public AccountDaoImpl(ConnectionSource connectionSource)
? ? ? throws SQLException {
? ? ? ? super(connectionSource, Account.class);
? ? }
}
要讓自定義DAO類生效,需要將其指定到對應(yīng)實體中@DatabaseTable的daoClass屬性上牧嫉。
@DatabaseTable(daoClass = AccountDaoImpl.class)
public class Account {
? …
}
2.5 ?ORMLite支持的數(shù)據(jù)庫類型
2.6 ?結(jié)合使用?Tying It All Together
基本流程
// h2為例剂跟,
String databaseUrl = "jdbc:h2:mem:account";
JdbcConnectionSource connectionSource =
? new JdbcConnectionSource(databaseUrl);
// 通過connectionSource實例化Dao
AccountDaoImpl accountDao = new AccountDaoImpl(connectionSource);
// 如果需要創(chuàng)建表减途,則調(diào)用下面的call
TableUtils.createTable(connectionSource, Account.class);
// 創(chuàng)建Account的一個實例
Account account = new Account("Jim Coakley");
// 持久化account對象到數(shù)據(jù)庫
accountDao.create(account);
…
// 銷毀數(shù)據(jù)源關(guān)閉潛在連接
connectionSource.destroy();
2.7 ?創(chuàng)建表和schema2.7.1 ?TableUtils類
? ? ? ? TableUtils 類提供了一系列靜態(tài)方法,用于創(chuàng)建和刪除表曹洽,以及提供schema語句鳍置。
?createTable(ConnectionSource, Class) ?用于創(chuàng)建表,返回成功的語句數(shù)
? ? ? ? TableUtils.createTable(connectionSource, Account.class);
?createTableIfNotExists(ConnectionSource, Class)?同上送淆,但不支持所有類型的數(shù)據(jù)庫
?createTable(ConnectionSource, DatabaseTableConfig)?同上税产,
getCreateTableStatements(ConnectionSource, Class)?
createTable(ConnectionSource, DatabaseTableConfig)功能同上,不過通過一個DatabaseTableConfig對象類表示需要創(chuàng)建的表的字段和字段類型偷崩。
createTableIfNotExists(ConnectionSource, DatabaseTableConfig)?功能同上辟拷,但不支持所有的數(shù)據(jù)庫。
dropTable(ConnectionSource, Class, boolean ignoreErrors)?刪除表阐斜,不能恢復(fù)衫冻,慎用。ignoreErrors參數(shù)谒出,如
果刪除時隅俘,表沒有創(chuàng)建,那么將ignoreErrors設(shè)為true則忽視所有異常笤喳。
dropTable(ConnectionSource, DatabaseTableConfig, boolean ignoreErrors)?刪除表为居,同上
getCreateTableStatements(ConnectionSource, Class)?類似于createTable,但是該方法返回的是一個語句列表杀狡,
這個列表可用于創(chuàng)建一個類蒙畴,在部分數(shù)據(jù)庫的初始化過程中,比較有用呜象。
getCreateTableStatements(ConnectionSource, DatabaseTableConfig)?同上
clearTable(ConnectionSource, Class)清除所有數(shù)據(jù)
clearTable(ConnectionSource, DatabaseTableConfig)?使用DatabaseTableConfig清除所有數(shù)據(jù)
2.7.2 TableCreator類
TableCreator類是為Spring設(shè)計的膳凝,但是在其他的配置中也可用。它通過ConnectionSource和DAOs列表配置董朝。
如果系統(tǒng)屬性ormlite.auto.create.tables被設(shè)為true則鸠项,與DAOs關(guān)聯(lián)的表會被自動創(chuàng)建。如果系統(tǒng)屬性
ormlite.auto.drop.tables屬性被設(shè)為true子姜,則會自動刪除表。這點在測試的時候比較有用楼入。你可以在測試開始的腳
本中設(shè)置系統(tǒng)屬性哥捕,并在生產(chǎn)腳本中關(guān)閉腳本。
List> daoList = new ArrayList>();
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 ?標(biāo)識列(字段)
? ? 數(shù)據(jù)庫行可以通過特定的id列標(biāo)識嘉熊。行本身不需要一個標(biāo)識字段遥赚,但是許多DAO操作(update, delete, refresh
)需要一個表示字段。這個標(biāo)識字段可以有用戶指定也可以由數(shù)據(jù)庫自動生成阐肤。數(shù)據(jù)行中id列的值時唯一的凫佛,如果需
要根據(jù)id操作數(shù)據(jù)讲坎,則必須指定id字段,可以通過下列三種方法中的一種愧薛,且只允許用一種指定晨炕。@DatabaseField屬
性的id,generatedId, generatedIdSequence
2.8.1 通過id指定
例如:
public class Account {
? ? @DatabaseField(id = true)
? ? private String name;
? ? …
}
使用:
Account account = accountDao.queryForId("John Smith");
if (account == null) {
? ? // the name "John Smith" does not match any rows
}
2.8.2 通過generatedId指定
可以通過long或者int型屬性生成標(biāo)識字段,數(shù)據(jù)行的字段會自動生成
例如:
public class Order {
? ? @DatabaseField(generatedId = true)
? ? private int id;
? ? …
}
當(dāng)訂單對象被創(chuàng)建并被存儲到數(shù)據(jù)庫中的時候毫炉,生成的id值會被返回并被設(shè)置給對象瓮栗,大多數(shù)數(shù)據(jù)庫類型,生成的id
值從1開始瞄勾,并每次遞增1费奸。
使用:
//通過指定id創(chuàng)建對象
Order order = new Order("Jim Sanders", 12.34);
…
orderDao.create(order);
System.out.println("Order id " + order.getId() +
? ?" was persisted to the database");
//查詢id為1372的訂單對象
order = orderDao.queryForId(1372);
if (order == null) {
? ?// none of the order rows have an id of 1372
}
2.8.3 通過generatedIdSequence創(chuàng)建id
有些數(shù)據(jù)庫使用序列號生成器提供id值,如果你使用generatedId = true創(chuàng)建數(shù)據(jù)庫进陡,則序列名會由ORMLite自動生
成愿阐,不過,你需要設(shè)置一個序列蜜瓜匹配現(xiàn)有的schema趾疚,你可以使用generatedIdSequence值换况。
例如:
public class Order {
? ? @DatabaseField(generatedIdSequence = "order_id_seq")
? ? private int id;
? ? …
}
2.9 DAO使用
通過使用DAO的方法,下列數(shù)據(jù)庫操作可以很輕松的完成盗蟆。
?1. 創(chuàng)建并持久化對象到數(shù)據(jù)庫
? ? ? Account account = new Account();
? ? ? account.name = "Jim Coakley";
? ? ? accountDao.create(account);
? ?2. 通過id列查詢
? ? ? Account account = accountDao.queryForId(name);
? ? ? if (account == null) {
? ? ? ? account not found handling …
? ? ? }
??3. 更新域數(shù)據(jù)庫關(guān)聯(lián)的對象的數(shù)據(jù)行戈二。
? ? ? account.password = "_secret";
? ? ? accountDao.update(account);
4. 在數(shù)據(jù)庫數(shù)據(jù)發(fā)生改變時刷新對象,需要id值喳资。
? ? ? accountDao.refresh(account);
??5. 刪除數(shù)據(jù)行觉吭。數(shù)據(jù)庫中刪除后,內(nèi)存中持有的數(shù)據(jù)庫還可用仆邓。
? ? ? accountDao.delete(account);
??6. 通過DAO對象遍歷數(shù)據(jù)行鲜滩。DAO本身也是一個迭代器,因此可以直接遍歷數(shù)據(jù)庫數(shù)據(jù)行节值。
? ? ? // page through all of the accounts in the database
? ? ? for (Account account : accountDao) {
? ? ? ? ?System.out.println(account.getName());
? ? ? }
? ? ? 你必須遍歷迭代器的所有數(shù)據(jù)庫對象徙硅,并關(guān)閉潛在的sql對象。 如果你沒有通過一個循環(huán)遍歷所有的數(shù)據(jù)搞疗,
ORMLite并不會關(guān)閉潛在對象嗓蘑,數(shù)據(jù)庫的連接會被弱化并且在后面被GC回收,這回導(dǎo)致程序Bug匿乃,所以最好使用一個
try...finally包裝迭代器桩皿。下面的情況是錯誤的“必須遍歷所有的對象”。
? ? ? for (Account account : accountDao) {
? ? ? ? ?if (account.getName().equals("Bob Smith")) {
? ? ? ? ? ?// you can't return, break, or throw from here
? ? ? ? ? ?return account;
? ? ? ? ?}
? ? ? }
??7. 直接使用迭代器
? ? ? 你也可以選擇直接使用迭代器幢炸,因為for循環(huán)式最佳的泄隔。這樣允許你使用try...finally達到一種更好的模式,
如:
? ? ? CloseableIterator 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(); ? ?
? ? ? }
? ?8. 獲得一個包裝迭代器“wrapped iterable”
? ?CloseableWrappedIterable wrappedIterable =
? ? ? ?accountDao.getWrappedIterable();
? ? ? ?try {
? ? ? ? ? for (Account account : wrappedIterable) {
? ? ? ? ? ? ? …
? ? ? ? ? }
? ? ? ?} finally {
? ? ? ? ? wrappedIterable.close();
? ?}
2.10 ?索引屬性
? ?id字段默認是索引屬性宛徊,非id字段在DatabaseField屬性屬性中指定index值為true佛嬉,所以優(yōu)化查詢逻澳,在表被刪除
時,索引也會被刪除暖呕。
? ?public class Account {
? ? ? ?@DatabaseField(id = true)
? ? ? ?private String name;
? ? ? ?// 給city屬性索引索引斜做,便于款速查詢更大的表
? ? ? ?@DatabaseField(index = true)
? ? ? ?private String city;
? ? ? ?…
? ?}
? ?索引名默認為account_city_idx,可以通過一個indexName=“othername”指定其他的索引名稱。如果經(jīng)常通過兩
個字段進行查詢缰揪,可以通過為兩個字段設(shè)置相同的索引名陨享,如:
? ?@DatabaseField(indexName = "account_citystate_idx")
? ?private String city;
? ?@DatabaseField(indexName = "account_citystate_idx")
? ?private String state;
? ?這種情況下,如果只根據(jù)其中的一個字段查詢钝腺,則并不會優(yōu)化查詢抛姑,不同的數(shù)據(jù)庫類型,單字段索引和多字段索
引的效率比較可能不行同艳狐。
? ?創(chuàng)建唯一索引可以通過@DatabaseField注解的uniqueIndex=true和uniqueIndexName='indexname'屬性指定定硝。這樣
,效果上和上面的設(shè)置時一樣的毫目,但是這樣可以創(chuàng)建確保沒有兩行數(shù)據(jù)具有相同的索引屬性值蔬啡。
2.11 ?原生的SQL語句問題
2.11.11 原生的查詢操作
? ? 1. 使用DAO中的queryRaw方法創(chuàng)建原生數(shù)據(jù)庫查詢,這個方法會返回一個GenericRawResult對象镀虐,代表一個字符
串?dāng)?shù)組箱蟆,對象數(shù)組,或者用戶包裝對象的數(shù)組刮便。 可以查看HenericRaeResult的文檔獲取更多用法空猜。
? ? // find out how many orders account-id #10 has
? ? GenericRawResults rawResults = orderDao.queryRaw( "select count(*) from orders where
account_id = 10");
? ? // there should be 1 result
? ? List results = rawResults.getResults();
? ? // the results array should have 1 value
? ? String[] resultArray = results.get(0);
? ? // this should print the number of orders that have this account-id
? ? System.out.println("Account-id 10 has " + resultArray[0] + " orders");
? ?2. 如果喜歡使用preparedStatementString()方法的話,也可以使用QueryBuilder創(chuàng)建原生查詢語句恨旱,詳情可以
查看QueryBuilderBasic這節(jié)辈毯。
? ? QueryBuilder qb = accountDao.queryBuilder();
? ? qb.where().ge("orderCount", 10);
? ? results = accountDao.queryRaw(qb.prepareStatementString());
? ?3. 如果需要使用QueryBuilder攜帶參數(shù)創(chuàng)建原生查詢語句的話們可以使用下列的方法:
? ? QueryBuilder qb = accountDao.queryBuilder();
? ? // we specify a SelectArg here to generate a ? in statement string below
? ? qb.where().ge("orderCount", new SelectArg());
? ? // the 10 at the end is an optional argument to fulfill SelectArg above
? ? results = accountDao.queryRaw(qb.prepareStatementString(), 10);
? ?4. 也可以使用下面的方式攜帶參數(shù)創(chuàng)建原生查詢
? ?QueryBuilder qb = accountDao.queryBuilder();
? ?// select 2 aggregate functions as the return
? ?qb.selectRaw("MIN(orderCount)", "MAX(orderCount)");
? ?// the results will contain 2 string values for the min and max
? ?results = accountDao.queryRaw(qb.prepareStatementString());
? ?String[] values = results.getFirstResult();
? ?5. 對于數(shù)據(jù)量大的結(jié)果集,應(yīng)該考慮使用GenericRawResults對象的iterator()方法搜贤,這會使用到數(shù)據(jù)庫分頁谆沃。
例如:
? ?// return the orders with the sum of their amounts per account
? ?GenericRawResults rawResults =
? ?orderDao.queryRaw("select account_id,sum(amount) from orders group by account_id");
? ?// page through the results
? ?for (String[] resultArray : rawResults) {
? ? ? System.out.println("Account-id " + resultArray[0] + " has "
? ? ? ?+ resultArray[1] + " total orders");
? ?}
? ?rawResults.close();
? ?6. ?如果你只需要查詢單個值(如聚合函數(shù)MAX的值),則可以使用queryRawValue(...)方法:
? ?long maxUnits = orderDao.queryRawValue("select max(units) from orders");
? ?7. ?如果你的部分屬性值不能被合適地轉(zhuǎn)換成字符串仪芒,并且你在結(jié)果字段中傳遞了返回類型唁影,那么可以返回屬性
為Object[]類型,如下:
? ?// return the orders with the sum of their amounts per account
? ?GenericRawResults rawResults =
? ?orderDao.queryRaw(
? ? ? ?"select account_id,sum(amount) from orders group by account_id",
? ? ? ?new DataType[] { DataType.LONG, DataType.INTEGER });
? ? ? ?//page through the results
? ? ? ?for (Object[] resultArray : rawResults) {
? ? ? ?System.out.println("Account-id " + resultArray[0] + " has "
? ? ? ?+ resultArray[1] + " total orders");
? ?}
? ?rawResults.close();
? ?注意: select * 可能會根據(jù)數(shù)據(jù)庫的類型返回不同的orders的屬性順序桌硫。 為了確保返回的數(shù)據(jù)類型數(shù)組與返回
的字段相匹配夭咬,你必須明確指定屬性,并且不能為SQL 的 *铆隘。
? ?8. ?你也可以通過傳遞一個RawRowMapper對象,將返回的結(jié)果映射到你自己的對象中南用。 這樣會通過一個字符串?dāng)?shù)
組調(diào)用映射對象膀钠,并允許將字符創(chuàng)轉(zhuǎn)換到對象中掏湾。DAO提供了一個默認的RawRowMapper,可以通過
orderDAO.getRawRowMapper()獲得,這個對象知道如何將字符串?dāng)?shù)組轉(zhuǎn)換到對象中肿嘲。
? ?如果結(jié)果比較復(fù)雜融击,你也可以自定義Mapper,如:
? ?// return the orders with the sum of their amounts per account
? ?GenericRawResults rawResults =
? ?orderDao.queryRaw(
? ? ? "select account_id,sum(amount) from orders group by account_id",
? ? ? new RawRowMapper() {
? ? ? ? ? ? public Foo mapRow(String[] columnNames,
? ? ? ? ? ? ? String[] resultColumns) {
? ? ? ? ? ? ? ? return new Foo(Long.parseLong(resultColumns[0]),
? ? ? ? ? ? ? ? ? ? Integer.parseInt(resultColumns[1]));
? ? ? ? ? ? ? }
? ? ? });
? ?// page through the results
? ?for (Foo foo : rawResults) {
? ? ?System.out.println("Account-id " + foo.accountId + " has "
? ? ?+ foo.totalOrders + " total orders");
? ?}
? ?rawResults.close();
? ?注意: 查詢和結(jié)果字符串可能根據(jù)不同的數(shù)據(jù)庫有不同的情況雳窟。例如:
? ?1. ?有些數(shù)據(jù)庫要求字段名必須是大寫尊浪,有些則要求是小寫。
? ?2. ?如果字段名或者表名有保留的話封救,你可能必須應(yīng)用他們拇涤。
? ?3. ?結(jié)果字段名也可能是大寫或者小寫。
? ?4. ?select * 可能根據(jù)數(shù)據(jù)庫類型返回的順序不同誉结。
? ?注: 和其他ORMLite迭代器一樣鹅士,你必須遍歷迭代器中的所有結(jié)果,以使語句自動關(guān)閉惩坑,或者調(diào)用
GeneratedRawResults.close()方法確保迭代器及相關(guān)的數(shù)據(jù)庫連接關(guān)閉掉盅。
? ?注: 如果你正在使用QueryBuilder#preparedStatementString()方法創(chuàng)建查詢,則可能會自動添加一個id列以舒。
2.11.2 ?原生的更新語句
? ?在DAO的函數(shù)不滿足你的靈活性時趾痘,可能要用到原生更新語句,更新語句必須包含保留關(guān)鍵字 INSERT, DELETE,
或者UPDATE蔓钟,例如:
? ?fooDao.updateRaw("INSERT INTO accountlog (account_id, total) " + "VALUES ((SELECT account_id,sum
(amount) FROM accounts))永票;
2.11.3 ?原生執(zhí)行語句
? ?在DAO的函數(shù)不滿足你的靈活性時,可能要用到原生執(zhí)行語句修改表奋刽。
? ?fooDao.executeRaw("ALTER TABLE accountlog DROP COLUMN partner");
2.12 外部對象屬性
? ?ORMLite支持外鍵的概念瓦侮,既一個對象的一個或者多個屬性對應(yīng)相同數(shù)據(jù)庫中其他表中的一個對象。例如佣谐,如果有
一個Order對象肚吏,并且每個Order具有一個對應(yīng)的Account對象,那么狭魂,這個Order對象可能具有一個外部對象的
Account屬性罚攀。對于這個外部對象屬性,只有Account的id屬性會被持久化到Order表中作為account_id列的值雌澄,例如
斋泄,Order類像下面這樣:
? ?@DatabaseTable(tableName = "orders")
? ?public class Order {
? ? ? @DatabaseField(generatedId = true)
? ? ? private int id;
? ? ? @DatabaseField(canBeNull = false, foreign = true)
? ? ? private Account account;
? ? ? …
? ?}
? ?當(dāng)訂單表創(chuàng)建的時候,會生成下面的語句
? ?CREATE TABLE `orders`(`id` INTEGER AUTO_INCREMENT , `account_id` INTEGER,
? ? ? PRIMARY KEY (`id`));
? ?注:屬性名并不叫account镐牺,而是account_id炫掐。 如果你需要通過這個屬性去查詢的話,應(yīng)該指定為account_id,
或者是通過DatabaseField注解的columnName參數(shù)指定一個字段名睬涧。
? ?通過外步對象創(chuàng)建屬性的時候募胃,一定注意旗唁,外在對象不會自動被創(chuàng)建。如果你的外在對象有一個數(shù)據(jù)庫提供的id
痹束,那么检疫,你需要在這個對象被引用之前創(chuàng)建這個id,例如:
? ?Account account = new Account("Jim Coakley");
? ?accountDao.create(account);
? ?// this will create the account object and set any generated ids
// now we can set the account on the order and create it
? ?Order order = new Order("Jim Sanders", 12.34);
? ?order.setAccount(account);
? ?…
? ?orderDao.create(order);
? ?如果你想要讓他們在某些情況下自建祷嘶,可以使用foreignAutoCreate設(shè)置屎媳,參考foreignAutoCreate
? ?當(dāng)你查詢一個訂單時,你會獲得一個account的屬性對象论巍,這個對象只有id屬性被設(shè)定了值烛谊,其他屬性都是默認值
。如果你需要使用這個account對象的其他值环壤,則必須調(diào)用accountDAO類的refresh方法獲得這個Account對象的屬性
晒来。
? ?Order order = orderDao.queryForId(orderId);
? ?System.out.println("Account-id on the order should be set: " + order.account.id);
? ?// this should print null for order.account.name
? ?System.out.println("But other fields on the account should not be set: " + order.account.name);
? ?// so we refresh the account using the AccountDao
? ?accountDao.refresh(order.getAccount());
? ?System.out.println("Now the account fields will be set: " + order.account.name);
? ?也可以使用foreignAutoRefresh設(shè)置自動刷新外部對象的數(shù)據(jù)。參考foreignAutoRefresh.
? ?注意: 由于我們使用到刷新郑现,所以外部對象必須有id屬性湃崩。
? ?你可以使用不同的方式查詢外部對象屬性。下面的例子展示了查詢匹配所有account屬性的訂單的代碼接箫。因為id屬
性石name攒读,所以你可以通過account的name屬性進行查詢。
? ?// query for all orders that match a certain account
? ?List results =
? ?orderDao.queryBuilder().where().eq("account_id", account.getName()).query();
? ?或者辛友,你可以讓ORMLite從account對象中取出id屬性薄扁,下面的代碼與上面的代碼等價:
? ?// ORMLite will extract and use the id field internally
? ?List results = orderDao.queryBuilder().where().eq("account_id", account).query();??
2.13 ?外部集合屬性
? ?在上一屆的指南中我們給出了訂單類具有一個外部對象屬性的實例。外部集合允許你添加一個訂單集合到賬戶表
中废累。無論何時邓梅,當(dāng)賬戶對象通過查詢語句返回,或者通過DAO對象刷新時邑滨,一個獨立的查詢會創(chuàng)建日缨,用于查詢對應(yīng)的
訂單,并且將這個訂單集合設(shè)置到賬戶對象中掖看。集合中所有的訂單都有一個關(guān)聯(lián)的外部對象魚賬戶對象匹配匣距。
? ?public class Account {
? ? ? ?…
? ? ? ?@ForeignCollectionField(eager = false)
? ? ? ?ForeignCollection orders;
? ? ? ?…
? ?}
? ?上面的例子顯示,@ForeignCollectionField注解表明了訂單屬性是一個與賬戶相匹配的訂單集合哎壳。訂單的屬性類
型必須是@ForeignCollection或者是Collection毅待,其他類型的集合不支持,因為他們有太多方法要支持归榕,太過
重量級尸红。@ForeignCollectionField注解支持的屬性包括下面這些:
??eager
? ?有兩種類型的外部集合:eager和lazy,如果設(shè)置eager為true,則獨立的查詢語句會被創(chuàng)建驶乾,對應(yīng)的訂單會被存
儲在一個集合中邑飒。如果eager設(shè)為false(默認值)循签,則集合會被認為是“l(fā)azy”的级乐,只有集合中的方法被調(diào)用時,才
會調(diào)用DAO.iterator()方法县匠,遍歷數(shù)據(jù)庫风科。
? ? 注:默認情況下,如果如果你有一個eager類型的對象集合乞旦,并且他們本身也有eager集合贼穆,那么內(nèi)部的集合會
因為性能原因被創(chuàng)建為lazy的。如果需要改變這一點的話兰粉, 可以查看下面的maxEagerLevel設(shè)置故痊。
??maxEagerLevel
? ?這個屬性能設(shè)置一個eager外部集合的外部集合擴展次數(shù)。如果你查詢A玖姑,并且A具有一個外部eager集合屬性B愕秫, B
具有一個外部集合屬性C,...焰络,無論何時戴甩,當(dāng)你查詢A的時候,一些列的數(shù)據(jù)庫操作會發(fā)生闪彼。莫仍情況下甜孤,這個值為1
,表示如果你查詢A畏腕,那么集合B會以eager方式獲得缴川,但是B中的每個對象的eager集合C會以lazy集合的方式加載。你
應(yīng)該根據(jù)自己的實際情況設(shè)置這個值描馅。
??columnName
? ?列名把夸。只有當(dāng)你想要匹配傳遞到DAO.assignEmptyForeignCollection(Object, String)中的string,或者指定想
要通過queryBuilder流昏。selectColumn(...)返回的集合時使用扎即。
??orderColumnName
? ?orderAscending
? ?foreignFieldName
2.14 支持DAO的對象
下面是讓對象本身支持數(shù)據(jù)庫操作,而不是使用DAO進行的ORM模式的另外一種方式况凉。例如谚鄙,給定一個數(shù)據(jù)對象foo,可以調(diào)用foo.refresh()而不是調(diào)用fooDao.refresh(foo)。默認是使用Dao類刁绒,這樣可以讓你的數(shù)據(jù)類擁有它自己的層次闷营,并將數(shù)據(jù)庫代碼和Dao分離。不過,如果你樂意使用這種模式的話傻盟,可以使用BaseDaoEnable類速蕊。
? ?所有可以屬性自身的類都需要繼承BaseDaoEnable類。例如:
@DatabaseTable(tableName = "accounts")
public class Account extends BaseDaoEnabled {
? ? @DatabaseField(id = true)
? ? private String name;
? ? @DatabaseField(canBeNull = false)
? ? private String password;
? ? …
? ? 第一次創(chuàng)建對象時娘赴,需要使用DAO對象规哲,或者你需要設(shè)置dao到對象中使其自建。
? ? account.setDao(accountDao);
? ? account.create();
? ? 不過诽表,無論何時唉锌,一個對象作為ORMLite的查詢結(jié)果返回時,DAO已經(jīng)被設(shè)置到這個對象中竿奏。
? ? Account account = accountDao.queryForId(name);
? ? account.setPassword(newPassword);
? ? account.update();
? ?這一點對外部屬性也是同樣的袄简。
? ? Order order = orderDao.queryForId(orderId);
? ? // load all of the fields from the account
? ? order.getAccount().refresh();
? ?BaseDaoEnable的javadoc具有最新的自操作列表,不過泛啸,目前這種類能做的內(nèi)容如下:
? ?create
? ?使用DAO或者調(diào)用對象的setDao()方法绿语。
? ?refresh
? ?刷新對象,以免其在數(shù)據(jù)庫中有更新候址。
? ?update
? ?對象在內(nèi)容中改變后吕粹,將數(shù)據(jù)更新到數(shù)據(jù)庫。
? ?updateId
? ?如果需要更新對象的id宗雇,必須使用這個方法昂芜。不能改變對象的id屬性,然后調(diào)用update方法赔蒲,否則數(shù)據(jù)這個對象
無法找到泌神。
? ?delete
? ?從數(shù)據(jù)庫中刪除對象。