I am stuck for 4 days on the same issue so I hope getting some help hear. I am trying to load data to a database through an SQL script but often when I run the app for the first time I have an error :
java.lang.RuntimeException: Unable to start activity ComponentInfo{small.app.beeroclock/small.app.beeroclock.MainActivity}: java.lang.IllegalStateException: Pre-packaged database has an invalid schema: Country(small.app.beeroclock.db.Country).
Expected:
TableInfo{name='Country', columns={country_name=Column{name='country_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, country_code=Column{name='country_code', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[], indices=[Index{name='index_Country_country_code', unique=false, columns=[country_code]}]}
Found:
TableInfo{name='Country', columns={}, foreignKeys=[], indices=[]}
Thing is I don't undestand the Pre-packaged database has an invalid schema cause my database is based on the Entities :
@Entity
data class City(
@NotNull
@PrimaryKey
val name: String,
@NotNull
val lat: Double,
@NotNull
val lng: Double,
@NotNull
val country_code: String
) {
}
And here the the appdatabase class :
@Database(
entities = arrayOf(Country::class, Timezone::class, Zone::class, City::class),
version = 1
)
abstract class AppDatabase : RoomDatabase() {
abstract fun countryDAO(): CountryDAO
abstract fun timezoneDAO(): TimezoneDAO
abstract fun zoneDAO(): ZoneDAO
abstract fun cityDAO(): CityDAO
}
lateinit var _context: Context
@Volatile
private lateinit var INSTANCE: AppDatabase
fun getInstance(context: Context): AppDatabase {
synchronized(AppDatabase::class.java) {
if (!::INSTANCE.isInitialized) {
_context = context
INSTANCE = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).addCallback(rdc).fallbackToDestructiveMigration()
.build()
//.addCallback(rdc)
}
return INSTANCE;
}
}
var rdc: RoomDatabase.Callback = object : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
//INSERT INTO `country` VALUES ('AF','Afghanistan')
//TODO : Issue to insert cities
try {
db.beginTransaction()
_context.assets.open("sql/timezonedb.sql").bufferedReader().forEachLine {
db.execSQL(it)
}
db.setTransactionSuccessful();
Log.d("Callback", "The creation of the db is done")
} catch (e: Exception) {
e.printStackTrace()
Log.d("Callback", "Issue with the database import")
} finally {
db.endTransaction();
}
}
override fun onOpen(db: SupportSQLiteDatabase) {
}
}
I guess it is not coming from the sql file itself because if, so I would have a sql error.
If anyone can highlight me I would really appreciate that :D
Regardss
Ok I figure a way to do what I want but I think it not that easy (for new bee of db like me).
So to anyone with the same issue this I how I proceed.
First export the schema of the db using : exportSchema property in the db class
@Database(
entities = arrayOf(Country::class, Timezone::class, Zone::class, City::class),
version = 1,
exportSchema = true
)
And adding the needed properties in the gradle module file :
apply plugin: 'kotlin-kapt'
android {
.....
defaultConfig {
......
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
}
}
}
}
After rebuilding the project you should get a json file under ../app/schema This JSON file contain all you need to create a db in sql. I extract the "createSql" line and replace the ${TABLE_NAME} by the real name :
"tableName": "Country",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`country_code` TEXT NOT NULL, `country_name` TEXT NOT NULL, PRIMARY KEY(`country_code`))",
become :
createSql": "CREATE TABLE IF NOT EXISTS `Country` (`country_code` TEXT NOT NULL, `country_name` TEXT NOT NULL, PRIMARY KEY(`country_code`));
So with those queries I created a SQL file.
Now to get a db file I use DB browser by SQLite : https://sqlitebrowser.org/
From there I created a new db file and run the sql file in it.
Finally, I added the db file to my android project under the assets folder (create a new one if you have none) and add the command in the db builder to create from a db file :
.createFromAsset("fileName.db")
Please leave comment if not clear.
Regards