记使用LitePal中偶然发现的一个问题。
最近一个小项目中需要保存数据,考虑到方便性和实际项目规模使用LitePal。需求中有一项需要在保存文件过程中如果文件名相同则覆盖原有数据。很直观的想法是先删除之前有相同文件名的所有数据,再添加新数据。
List<InputValueInfo> data = getInfo();
if (isThisNameUsed(text)){
LitePal.deleteAll(InputValueInfo.class, "fileName = ?", text);
}
for (InputValueInfo d : data_copy){
d.setFileName(text);
boolean result = d.save();
}
但实际测试功能过程发现,保存到新文件后,紧接着再以原数据直接覆盖这个新文件时,数据并不会被保存下来。即若按直观的想法处理后,数据表为空。
断点观察源码后发现方法onSave()里面会根据判断对象是否已经保存的方法:isSaved()决定是保存该对象还是更新该对象。
void onSave(LitePalSupport baseObj) throws SecurityException, IllegalArgumentException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException {
String className = baseObj.getClassName();
List<Field> supportedFields = getSupportedFields(className);
List<Field> supportedGenericFields = getSupportedGenericFields(className);
Collection<AssociationsInfo> associationInfos = getAssociationInfo(className);
if (!baseObj.isSaved()) {
analyzeAssociatedModels(baseObj, associationInfos);
doSaveAction(baseObj, supportedFields, supportedGenericFields);
analyzeAssociatedModels(baseObj, associationInfos);
} else {
analyzeAssociatedModels(baseObj, associationInfos);
doUpdateAction(baseObj, supportedFields, supportedGenericFields);
}
}
于是进一步观察isSaved()方法。发现源码根据baseObjId判断该对象是否已被保存。
public boolean isSaved() {
return baseObjId > 0;
}
于是再进一步考察这个baseObjId变量,发现有一处usage的赋值行为类似于setter,于是发现了一个public对该变量赋值的方法assighBaseObjId()
public void assignBaseObjId(int baseObjId) {
this.baseObjId = baseObjId;
}
于是最终在最初直接obj.save()的方法前添加一行,即可解决问题。
obj.assignBaseObjId(0)
注:
直接新建列表新建对象再赋值域并没有起到作用,添加到新列表后的新对象即使只是使用了原对象的几个值域,同样会得到其同样的baseObjId。还望有大佬解答。