1. 程式人生 > >ORMLite使用中出現的問題及解決辦法

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日誌看不出問題時,最好是看下原始碼,這樣容易定位到問題點。