ORMLite使用中出現的問題及解決辦法
專案開發中,用到了ORMLite進行資料庫操作,其中有三個物件是一對多的關係,在使用過程中出現了一個奇怪的問題。
假設:三個類Company、Person、Car,
Company對應多個Person,Person對應多個Car。
1、出現的問題如下:
①、在Company和Person都聲明瞭外來鍵集合為eager=true,但是從資料庫中獲取的資料來看,Company擁有的Person集合是EagerForeignCollection的,Person擁有的Car物件
集合時LazyForeignCollection的(注:不知道為什麼會是這個情況,但這個是導致出現第二個問題的原因之一)
②、現在有兩個Activity: A和B,在A中查詢資料庫,獲取一個Company物件,將這個物件通過Intent傳遞給B,在B中取出Company物件,並通過這個物件獲取Car的資訊時,
會出現錯誤:
Caused by: java.lang.IllegalStateException: Internal DAO object is null. Maybe the collection was deserialized or otherwise constructed wrongly. Use dao.assignEmptyForeignCollection(…) or dao.getEmptyForeignCollection(…) instead
2、問題的分析:
問題①原因不明,問題②分析結果如下:
①:LazyForeignCollection是慢載入模式,在得到這個物件之後,這個物件中並沒有具體的物件集合,而是在每一次查資料的時候,直接從資料庫中查詢;
②:LazyForeignCollection繼承BaseForeignCollection,查詢資料庫是同過BaseForeignCollection#dao物件來進行查詢的
③:LazyForeignCollection實現了Serializable介面,可進行序列化,但是成員變數dao 使用transient修飾的,不參與序列化過程;
④:在B中拿到的Car集合時反序列化之後的LazyForeignCollection物件,因為Dao兌現不能序列化,所以為NUll
⑤:在B中檢視Car結合時,就會丟擲這個異常,可以從LazyForeignCollection的iterator方法來看:
public CloseableIterator<T> iterator() {
return this.closeableIterator(-1);
}
public CloseableIterator<T> closeableIterator(int flags) {
try {
return this.iteratorThrow(flags);
} catch (SQLException var3) {
throw new IllegalStateException("Could not build lazy iterator for " + this.dao.getDataClass(), var3);
}
}
public CloseableIterator<T> iteratorThrow(int flags) throws SQLException {
this.lastIterator = this.seperateIteratorThrow(flags);
return this.lastIterator;
}
private CloseableIterator<T> seperateIteratorThrow(int flags) throws SQLException {
//因為dao物件為NUll,所以就丟擲了這個異常
if(this.dao == null) {
throw new IllegalStateException("Internal DAO object is null. Maybe the collection was deserialized or otherwise constructed wrongly. Use dao.assignEmptyForeignCollection(...) or dao.getEmptyForeignCollection(...) instead");
} else {
return this.dao.iterator(this.getPreparedQuery(), flags);
}
}
3、解決問題2的方法之一,就是在從資料庫中查詢到Car資料之後,將資料從LazyForeignCollection中取出,放置到新的Collection物件中,
用Collection替換LazyForeignCollection,相當於在進行資料查詢操作之後,進行一次預載入操作:
//從資料庫中獲取資料之後,執行一次預載入操作:
Collection<Company> companies = companyDao.getAllCompanys();
if(companies!=null){
Iterator<Company> iteraCom = companies.iterator();
while(iteraCom.hasNext()){
Company company = iteraCom.next();
Collection<Person> person =company.getPersons();
if(person!=null) {
Iterator<Person> iteraPer = person.iterator();
while (iteraPer.hasNext()) {
//對Car集合進行一次預載入操作
iteraPer.next().getCars();
}
}
}
}
return companies;
public Collection<Car> getCars() {
if(this.cars==null){
return null;
}
if(this.cars instanceof LazyForeignCollection){
Collection<Car> tmp = new ArrayList<Car>();
Iterator<Car> iterator = this.cars.iterator();
while(iterator.hasNext()){
Car car = iterator.next();
tmp.add(car);
}
this.cars = tmp;
}
return cars;
}
程式碼修改之後,資料傳遞正常。
總結:在使用一些第三方開元框架時,如果使用過程中出現了BUG,通過log日誌看不出問題時,最好是看下原始碼,這樣容易定位到問題點。