项目开发中,用到了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日志看不出问题时,最好是看下源码,这样容易定位到问题点。