Ormlite全解析(非安卓)

添加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ù)庫中刪除對象。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末舞虱,一起剝皮案震驚了整個濱河市欢际,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌矾兜,老刑警劉巖损趋,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異椅寺,居然都是意外死亡浑槽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門返帕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桐玻,“玉大人,你說我怎么就攤上這事荆萤∧餮ィ” “怎么了铣卡?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長偏竟。 經(jīng)常有香客問我煮落,道長,這世上最難降的妖魔是什么踊谋? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任蝉仇,我火速辦了婚禮,結(jié)果婚禮上褪子,老公的妹妹穿的比我還像新娘量淌。我一直安慰自己,他們只是感情好嫌褪,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胚股,像睡著了一般笼痛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上琅拌,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天缨伊,我揣著相機與錄音,去河邊找鬼进宝。 笑死刻坊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的党晋。 我是一名探鬼主播谭胚,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼未玻!你這毒婦竟也來了灾而?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤扳剿,失蹤者是張志新(化名)和其女友劉穎旁趟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庇绽,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡锡搜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瞧掺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耕餐。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夸盟,靈堂內(nèi)的尸體忽然破棺而出蛾方,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布桩砰,位于F島的核電站拓春,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亚隅。R本人自食惡果不足惜硼莽,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望煮纵。 院中可真熱鬧懂鸵,春花似錦、人聲如沸行疏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酿联。三九已至终息,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贞让,已是汗流浹背周崭。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留喳张,地道東北人续镇。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像销部,于是被迫代替她去往敵國和親摸航。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容