kotlinandroid-roomandroid-room-prepackageddatabase

Room refuses loading in ANY data from the pre-packaged database, even if it was created using it's own autogenerated queries


For the past 4 hours I've been fighting with room to load in my pre-packaged database, I've read some posts that told me to try finding the _Impl.java file, and check the schema generated there, so I did, and moved my database into that schema, ran SQL queries to load in the data into that DB, imported it again and... enter image description here got hit again with the same toast message (also, why a toast and not just a log?), for reproductive examples I've tried loading in only one db entity, but that changed nothing and I've got no ideas left

Example query for creating an item:

INSERT INTO products (title, image, price, description, category, rating, numberOfRatings) VALUES ("Retro Cat-Eye Sunglasses", "https://uploads-ssl.webflow.com/5b105a0c66f2f636c7884a17/64063dbcad97bd421b437096_chatgpt.jpg", 29.95, "Retro-inspired cat-eye sunglasses for a vintage look.", "Accessories", 4.4, 148);

the database table creation query (generated by room):

CREATE TABLE IF NOT EXISTS `products` (`id` INTEGER NOT NULL, `title` TEXT NOT NULL, `price` REAL NOT NULL, `description` TEXT NOT NULL, `image` TEXT NOT NULL, `category` TEXT NOT NULL, `rating` REAL NOT NULL, `numberOfRatings` INTEGER NOT NULL, PRIMARY KEY(`id`))

the entity I've used:

@Entity(tableName = "products")
data class ProductEntity(
    @PrimaryKey val id: Int,
    val title: String,
    val price: Double,
    val description: String,
    val image: String,
    val category: String,
    val rating: Double,
    val numberOfRatings: Int
)

I followed the documentation, so I'm sure the room is able to find the correct asset (see image)

Any ideas will be appreciated, 'cause my sanity is gone


Solution

  • Ok I made it work... here's how:

    1. find the YourDatabaseName_Impl file (it usually is generated IF you see the same error, try pressing shift twice and searching for a field name from your Entity class)
    2. find the createAllTables function in the file and copy the SQL query that contains your table name (usually the first one)
    3. (edit: It may be worth to wipe the emulator data before this step) now open the place where your DB is created (in my case: a hilt module) add something like:
    val rdc = object : RoomDatabase.Callback() {
        override fun onCreate(db: SupportSQLiteDatabase) {
            val SQL_CREATE_TABLE = "PASTE HERE THE QUERY YOU JUST COPIED"
            db.execSQL(SQL_CREATE_TABLE)
            val contentValues = ContentValues()
            // here we are manually created an entity, your table schema is definitevely different, so change this!
            contentValues.put("id", 0)
            contentValues.put("price", 12.99)
            contentValues.put("title", "yes")
            contentValues.put("description", "no")
            contentValues.put("image", "maybe.jpg")
            contentValues.put("category", "nonbin")
            contentValues.put("rating", 12.5)
            contentValues.put("numberOfRatings", 101)
            db.insert("YOUR TABLE NAME", OnConflictStrategy.REPLACE, contentValues)
        }
    }
    

    at the top

    Then just add .addCallback(rdc) to the database builder, like so:

    Room.databaseBuilder(appContext, YourDatabaseNameHere::class.java, "YourDatabaseNameHereButSlightlyDifferentForRoomReasons.db")
                    .addCallback(rdc)
                    .build()
    

    This will (hopefully) create the db and the table + add ONE item to the table

    (Test the app here)

    if it all worked: find the device explorer tool in android studio select the correct emulator (on top) and then navigate to: data -> data -> (search here for your package name, or an app name for a dir with the matching name) -> databases how it will look

    then right click on the .db file and press "save as" and save it somewhere

    and you will have a working db, with a table that has the correct schema and an example item, now you should be able to insert other items into the table (usually done by queries) and after that you can take the db file, move it into the assets (in my case it's a folder inside assets named database) and do:

    Room.databaseBuilder(appContext, YourDatabaseName::class.java, "YourDatabaseNameHereButSlightlyDifferentForRoomReasons.db")
    //                .addCallback(rdc)
                    .createFromAsset("database/YourDatabaseName.db")
                    .build()
    

    but before: wipe the data off the device (just to be sure)

    and it... should work. hopefully.