Sorry for the wall of code, but I wanted to provid...
# android
v
Sorry for the wall of code, but I wanted to provide enough context for anyone who might be able to help. I wanted to ask here before posting a bug report ...
🧵 4
c
Post the Wall of code inside the thread of your post.
☝️ 1
v
Here goes: I'm hitting a problem using Room with a pre-packaged SQLite database. Here is the schema of the single table I'm trying to work with, copy-pasted from the SQLIte3 CLI:
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> .schema product
CREATE TABLE IF NOT EXISTS "product" (
"id"	INTEGER NOT NULL,
"slug"	TEXT NOT NULL UNIQUE,
"label"	TEXT NOT NULL UNIQUE,
"price"	NUMERIC NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT)
);
Here are my entity definition corresponding to this table, the DAO to access it, the
ViewModel
and the database setup:
@Entity(tableName = "product")
data class Product(
@PrimaryKey(autoGenerate = true)
val id: Int,
val slug: String,
val label: String,
val price: Double,
@Ignore val quantity: Int,
) {
constructor(id: Int, slug: String, label: String, price: Double) : this(id, slug, label, price, 0)
}
@Dao
interface ProductData {
@Query("SELECT * FROM product")
fun getAllProducts(): List<Product>
}
class ProductViewModel(private val data: ProductData) : ViewModel() {
val products = data.getAllProducts()
}
@Database(
version = 1,
entities = [Product::class],
exportSchema = false,
)
abstract class AppDatabase : RoomDatabase() {
abstract val product: ProductData
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
synchronized(this) {
return INSTANCE ?: Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"viscount.db"
)
.createFromAsset("data/viscount.db")
.build().also { INSTANCE = it }
}
}
}
}
here is how I set it up in my main activity:
class MainActivity : ComponentActivity() {
private val db by lazy { AppDatabase.getInstance(this) }
private val viewModel by viewModels<ProductViewModel>(
factoryProducer = {
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ProductViewModel(db.product) as T
}
}
}
)
// other code omitted for brevity
}
The error occurs on the line
return ProductViewModel(db.product) as T
and here is a partial log from LogCat:
java.lang.IllegalStateException: Pre-packaged database has an invalid schema: product(com.red_dove.viscount.Product).
Expected:
TableInfo{name='product', columns={id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}, label=Column{name='label', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, slug=Column{name='slug', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, price=Column{name='price', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='product', columns={id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='undefined'}, slug=Column{name='slug', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, label=Column{name='label', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, price=Column{name='price', type='NUMERIC', affinity='1', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
at androidx.room.RoomOpenHelper.onCreate(RoomOpenHelper.kt:73)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onCreate(FrameworkSQLiteOpenHelper.kt:244)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:432)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:336)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableOrReadableDatabase(FrameworkSQLiteOpenHelper.kt:232)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.innerGetDatabase(FrameworkSQLiteOpenHelper.kt:190)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getSupportDatabase(FrameworkSQLiteOpenHelper.kt:151)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.kt:104)
at androidx.room.SQLiteCopyOpenHelper.getWritableDatabase(SQLiteCopyOpenHelper.kt:71)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.kt:632)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.kt:451)
at com.red_dove.viscount.ProductData_Impl.getAllProducts(ProductData_Impl.java:31)
at com.red_dove.viscount.ProductViewModel.<init>(Data.kt:33)
at com.red_dove.viscount.MainActivity$viewModel$2$1.create(MainActivity.kt:27)
The only relevant difference I can see in the "expected" vs "found" lines is that we're expecting
id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}
but finding
id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='undefined'}
Can anyone explain why it finds
notNull=false
when by the table definiion clearly it should be marked as
notNull=true
, the expected value?
d
@Vinay Sajip The implication was you then remove the wall of code from the main channel (please). You can do that by editing your original message (up to certain point-in-time). This is general threaded-chat etiquette, not specific to Kotlin Slack. Thanks.