Closed freshteapot closed 8 years ago
If you have already investigated over the issue, could you please submit a pull request? Thanks.
you simply subclass the ModelSaver
class and provide your own implementation which logs what you need.
@agrosner I'm trying to add global insert
and update
logging as well. Here is a breadcrumb with another example and more information, but unfortunately I can't get it to work (I'm using DBFlow 3.1.1):
https://github.com/Raizlabs/DBFlow/issues/919
Here is what I have so far:
public class MyModelSaver extends ModelSaver<Model, Model, ModelAdapter<Model>> {
// public MyModelSaver() {
// setAdapter(FlowManager.getModelAdapter(Model.class));
// setModelAdapter(FlowManager.getModelAdapter(Model.class));
// }
@Override
@SuppressWarnings("unchecked")
public synchronized boolean update(@NonNull Model model, @NonNull DatabaseWrapper wrapper,
@NonNull ContentValues contentValues) {
return super.update(model, wrapper, contentValues);
}
@Override
@SuppressWarnings("unchecked")
public synchronized long insert(@NonNull Model model, @NonNull DatabaseStatement insertStatement) {
return super.insert(model, insertStatement);
}
@Override
@SuppressWarnings("unchecked")
public synchronized boolean delete(@NonNull Model model, @NonNull DatabaseWrapper wrapper) {
return super.delete(model, wrapper);
}
}
//public class MyModelSaver<TModel extends Model, TTable extends Model,
// TAdapter extends RetrievalAdapter & InternalAdapter> extends ModelSaver<TModel, TTable, TAdapter> {
//// public MyModelSaver() {
//// setAdapter(FlowManager.getModelAdapter(Model.class));
//// setModelAdapter(FlowManager.getModelAdapter(Model.class));
//// }
//
// @Override
// @SuppressWarnings("unchecked")
// public synchronized boolean update(@NonNull TTable model, @NonNull DatabaseWrapper wrapper,
// @NonNull ContentValues contentValues) {
// return super.update(model, wrapper, contentValues);
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public synchronized long insert(@NonNull TTable model, @NonNull DatabaseStatement insertStatement) {
// return super.insert(model, insertStatement);
// }
//
// @Override
// @SuppressWarnings("unchecked")
// public synchronized boolean delete(@NonNull TTable model, @NonNull DatabaseWrapper wrapper) {
// return super.delete(model, wrapper);
// }
//}
I've tried all permutations of the above but can never get it to compile.
I've also tried creating an anonymous instance of ModelSaver and overriding its insert(), update() and delete() methods so that I can add my own logging:
FlowManager.init(new FlowConfig.Builder(this).build());
{
for (Class<? extends Model> model : FlowManager.getDatabase("database").getModelClasses()) {
FlowManager.getModelAdapter(model).setModelSaver(new ModelSaver<Model, Model, ModelAdapter<Model>>() {
@Override
@SuppressWarnings("unchecked")
public synchronized boolean update(@NonNull Model model, @NonNull DatabaseWrapper wrapper, @NonNull ContentValues contentValues) {
return super.update(model, wrapper, contentValues);
}
@Override
@SuppressWarnings("unchecked")
public synchronized long insert(@NonNull Model model, @NonNull DatabaseStatement insertStatement) {
return super.insert(model, insertStatement);
}
@Override
@SuppressWarnings("unchecked")
public synchronized boolean delete(@NonNull Model model, @NonNull DatabaseWrapper wrapper) {
return super.delete(model, wrapper);
}
});
}
FlowLog.setMinimumLoggingLevel(FlowLog.Level.V);
}
No matter what I try, I always get:
Error:(73, 66) error: incompatible types: <anonymous ModelSaver<Model,Model,ModelAdapter<Model>>> cannot be converted to ModelSaver<CAP#1,CAP#1,ModelAdapter<CAP#1>>
where CAP#1 is a fresh type-variable:
CAP#1 extends Model from capture of ? extends Model
There is little to no information about this on the web. This was the only substantial answer I could find:
https://stackoverflow.com/a/20548655/539149
So it seems that generics are where Java really falls down (coincidentally that's the reason I left C++).
Here is another way to (possibly) log queries through ADB:
https://stackoverflow.com/questions/5966584/logging-sql-queries-in-android
But I need to be able to set a breakpoint where each query is called so that I can isolate an elusive TypeConverter issue.
If someone knows how to override ModelSaver, please post a solution thanks. Here are all the links I have on this:
https://github.com/Raizlabs/DBFlow/issues/422 https://github.com/Raizlabs/DBFlow/issues/820 https://github.com/Raizlabs/DBFlow/issues/677 https://self-learning-java-tutorial.blogspot.com/2014/03/wild-card-capture.html https://stackoverflow.com/questions/39684999/incompatible-types-somex-cannot-be-converted-to-cap1 https://stackoverflow.com/questions/21569868/try-to-do-typecast-but-getting-cap1-error
I managed to cobble this together. It's not ideal, because it sets the ModelSaver
inside getModelAdapter()
. But this at least provides places where breakpoints can be set to log all insert/update/delete:
// BaseModel inherited by all other models in the project
public abstract class MyBaseModel extends BaseModel {
@Override
public void insert() {
super.insert();
}
@Override
public void update() {
super.update();
}
@Override
public void delete() {
super.delete();
}
private class MyModelSaver extends ModelSaver<BaseModel, BaseModel, ModelAdapter<BaseModel>> {
@Override
@SuppressWarnings("unchecked")
public synchronized long insert(@NonNull BaseModel model, @NonNull DatabaseStatement insertStatement) {
ContentValues tempContentValues = new ContentValues();
getAdapter().bindToContentValues(tempContentValues, model);
Log.i("ModelSaver.insert()", getAdapter().getTableName() + " [" + tempContentValues.toString() + "]");
return super.insert(model, insertStatement);
}
@Override
@SuppressWarnings("unchecked")
public synchronized boolean update(@NonNull BaseModel model, @NonNull DatabaseWrapper wrapper, @NonNull ContentValues contentValues) {
ContentValues tempContentValues = new ContentValues();
getAdapter().bindToContentValues(tempContentValues, model);
Log.i("ModelSaver.update()", getAdapter().getTableName() + " [" + tempContentValues.toString() + "] where [" + getAdapter().getPrimaryConditionClause(model) + "]");
return super.update(model, wrapper, contentValues);
}
@Override
@SuppressWarnings("unchecked")
public synchronized boolean delete(@NonNull BaseModel model, @NonNull DatabaseWrapper wrapper) {
Log.i("ModelSaver.delete()", getAdapter().getTableName() + " where [" + getAdapter().getPrimaryConditionClause(model) + "]");
return super.delete(model, wrapper);
}
}
public ModelAdapter getModelAdapter() {
ModelAdapter modelAdapter = super.getModelAdapter();
if (!(modelAdapter.getModelSaver() instanceof MyModelSaver)) {
MyModelSaver modelSaver = new MyModelSaver();
modelSaver.setAdapter(modelAdapter);
modelSaver.setModelAdapter(modelAdapter);
modelAdapter.setModelSaver(modelSaver);
modelAdapter.getListModelSaver(); // calls modelAdapter.createListModelSaver() which sets modelAdapter.listModelSaver.modelSaver = modelSaver
}
return modelAdapter;
}
}
After writing this, I realized that probably all of the logic flows through MyBaseModel.insert()
, MyBaseModel.update()
and MyBaseModel.update()
so I'm not sure that the ModelSaver
is even necessary.
Also I recommend taking a look at ListModelSaver
because it calls ModelSaver
repeatedly (instead of doing multi-row operations via SQL) which is not performant in many cases. Maybe this has changed in DBFlow 4+ but I'm not certain.
Today, it is possible to get logging via:
for:
It would be great to get logging for:
Looking into the code. I think we just need to add the following:
To.