database records not being saved
Closed this issue · 12 comments
Hi,
I'm not being able to save records to db. even when i issue countAll(Model.class) after calling persist on the model instance I get 0 as as number of records (persist is called twice and i'm running the countAll after the first persist). whats wrong?
package .com.mh.model;
import android.content.Context;
import com.yahoo.squidb.android.AndroidOpenHelper;
import com.yahoo.squidb.data.ISQLiteDatabase;
import com.yahoo.squidb.data.ISQLiteOpenHelper;
import com.yahoo.squidb.data.SquidDatabase;
import com.yahoo.squidb.sql.Table;
public class ModelController extends SquidDatabase {
Context mContext;
public ModelController(Context context)
{
super();
mContext = context;
}
@Override
public String getName() {
return "enduser_pets.db";
}
@Override
protected int getVersion() {
return 9;
}
@Override
protected Table[] getTables() {
return new Table[]{
Model.TABLE
};
}
@Override
protected boolean onUpgrade(ISQLiteDatabase db, int oldVersion, int newVersion) {
mContext.deleteDatabase(getName());
return false;
}
@Override
protected ISQLiteOpenHelper createOpenHelper(String databaseName, OpenHelperDelegate delegate, int version) {
return new AndroidOpenHelper(mContext, getName(), delegate, getVersion());
}
}
ModelControler mController = new ModelController(getApplicationContext());
ModelClass mclass = new ModelClass();
mclass.setTitle("Hi");
mController.persist(mclass);
I can't say for sure if this is the cause of your specific problem or not, but your onUpgrade()
method would definitely cause some major issues:
mContext.deleteDatabase(getName())
would delete the db file out from under the SquidDatabase while it still has an open connection to it. The behavior if you do this is undefined; I think what you want is to callrecreate()
which will safely close the db, delete it, and create a new, empty one instead.- Returning false from onUpgrade means that you are indicating to the SquidDatabase that the migration has failed. In this case, the SquidDatabase would throw a MigrationFailedException, and since you're not overriding
onMigrationFailed
, the default implementation will just rethrow that exception, meaning it may never be attempting to persist your model in the first place.
I'd recommend you check out the Implementing database upgrades wiki page and follow the guidelines there for your onUpgrade method. If that doesn't solve your issue we'll probably need more information.
I modified the above mentioned changes, removed the mContext.deleteDatabase to recreate() and true as onUpgrade return value but still cant save data to the db...so what information is needed to be able to help me more? and thanks
If you come join our gitter chat at https://gitter.im/yahoo/squidb we can help you debug -- I think this will be easier than a back-and-forth on this issue.
@TableModelSpec(className = "ModelClass", tableName = "model")
class Model
{
@PrimaryKey
long model_id;
String title;
}
package com.mh.model;
import android.content.Context;
import com.yahoo.squidb.android.AndroidOpenHelper;
import com.yahoo.squidb.data.ISQLiteDatabase;
import com.yahoo.squidb.data.ISQLiteOpenHelper;
import com.yahoo.squidb.data.SquidDatabase;
import com.yahoo.squidb.sql.Table;
public class ModelController extends SquidDatabase {
Context mContext;
private static ModelController mModelController;
public static ModelController createDb(Context context)
{
if(mModelController == null)
{
mModelController = new ModelController(context);
}
return mModelController;
}
private ModelController(Context context)
{
super();
mContext = context;
}
@Override
public String getName() {
return "enduser_pets.db";
}
@Override
protected int getVersion() {
return 9;
}
@Override
protected Table[] getTables() {
return new Table[]{
ModelClass.TABLE
};
}
@Override
protected boolean onUpgrade(ISQLiteDatabase db, int oldVersion, int newVersion) {
mContext.deleteDatabase(getName());
return false;
}
@Override
protected ISQLiteOpenHelper createOpenHelper(String databaseName, OpenHelperDelegate delegate, int version) {
return new AndroidOpenHelper(mContext, getName(), delegate, getVersion());
}
}
My Model class and Model database
package pets_user.mahmoudhaddad.com.mh.pets_end_user.model;
import android.content.Context;
import com.yahoo.squidb.android.AndroidOpenHelper;
import com.yahoo.squidb.data.ISQLiteDatabase;
import com.yahoo.squidb.data.ISQLiteOpenHelper;
import com.yahoo.squidb.data.SquidDatabase;
import com.yahoo.squidb.sql.Table;
/**
* Created by mahmoudhadad on 8/23/16.
*/
public class ModelController extends SquidDatabase {
Context mContext;
private static ModelController mModelController;
public static ModelController createDb(Context context)
{
if(mModelController == null)
{
mModelController = new ModelController(context);
}
return mModelController;
}
private ModelController(Context context)
{
super();
mContext = context;
}
@Override
public String getName() {
return "enduser_pets.db";
}
@Override
protected int getVersion() {
return 11;
}
@Override
protected Table[] getTables() {
return new Table[]{
BusinessDetailModel.TABLE,
PetKindModel.TABLE,
ServiceModel.TABLE,
ServiceDetailModel.TABLE,
ProductModel.TABLE,
ProductDetailModel.TABLE,
BoardingServiceModel.TABLE,
BoardingServicePetModel.TABLE,
GroomingServiceModel.TABLE,
GroomingServicePetModel.TABLE,
ImportExportServiceModel.TABLE,
ImportExportServicePetModel.TABLE,
BusinessModel.TABLE
};
}
@Override
protected boolean onUpgrade(ISQLiteDatabase db, int oldVersion, int newVersion) {
recreate();
return true;
}
@Override
protected ISQLiteOpenHelper createOpenHelper(String databaseName, OpenHelperDelegate delegate, int version) {
return new AndroidOpenHelper(mContext, getName(), delegate, getVersion());
}
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.3'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "pets_user.mahmoudhaddad.com.mh.pets_end_user"
minSdkVersion 23
targetSdkVersion 23
multiDexEnabled = true
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:support-v4:23.4.0'
compile 'com.android.support:design:23.4.0'
compile 'com.yahoo.squidb:squidb:3.1.2'
compile 'com.yahoo.squidb:squidb-annotations:3.1.2'
compile 'com.yahoo.squidb:squidb-android:3.1.2' // For Android projects only
apt 'com.yahoo.squidb:squidb-processor:3.1.2'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
}
The calling method
for(int i =0 ; i < jsonArr.length; i++)
{
ModelClass mclass = new ModelClass();
mclass.setTitle("hi");
mController.persist(mclass);
}
I'm only getting this warning
ClassLoader referenced unknown path: /data/app/pets_user.mahmoudhaddad.com.mh.pets_end_user-2/lib/arm64
Caused by: android.database.sqlite.SQLiteException: no such column: service.id (code 1): , while compiling: SELECT service.id AS id, service.serviceId AS serviceId, service.parentServiceId AS parentServiceId, service.nameAr AS nameAr, service.nameEn AS nameEn, service.serviceType AS serviceType, service.isActive AS isActive, service.isPublished AS isPublished, service.price AS price, service.businessId AS businessId FROM service WHERE (service.serviceType=?) LIMIT 10
model spec
package pets_user.mahmoudhaddad.com.mh.pets_end_user.model;
import com.yahoo.squidb.annotations.TableModelSpec;
/**
* Created by mahmoudhadad on 8/29/16.
*/
@TableModelSpec(className = "ServiceModel", tableName = "service")
public class Service {
int id;
long service_id;
int parent_service_id = 0;
String name_En = "", service_type = "";
boolean isActive = false, isPublished = false;
}
Fixed. It was a build tools issue. removed the @PrimaryKey annotations and renamed fields to not have a trailing classname_id names and it worked..Thanks for your help
@mhadad I had a realization about a possible cause of your issue, just wanted to post it here so you saw it and were aware of the behavior. When you said it started working when you removed the @PrimaryKey
annotations, I had a suspicion that perhaps the problem was that you were setting an integer primary key column to some value before calling persist()
. SquiDB uses the SQLite rowid column as bookkeeping to determine whether or not a row "exists" when deciding on persist()
logic. SQLite treats any column that is an integer primary key as an alias to the rowid, so when you declare a column as an integer or long and tag it with @PrimaryKey
, SquiDB will use it for this bookkeeping instead. If such a column is set to a non-zero value before calling persist()
, the persist method will attempt to do an update on that rowid, rather than an insert -- but if that row doesn't exist yet, the update will of course fail and persist will return false.
You never posted a full example of your persist code using the actual model class you were using so I can't say for sure, but if you had an integer primary key column and were setting it to a value before calling persist, that would be a very likely cause of the behavior you were seeing. Hope it helps.