SQLite到Room迁移:decimal类型亲和性不匹配问题求助
解决方案
方法一:改用BigDecimal字段+类型转换器(推荐)
SQLite中decimal(13,4)的亲和性为NUMERIC(affinity=1),而Room默认将Double类型映射为REAL(affinity=4),手动设置typeAffinity=1会被字段类型覆盖。改用BigDecimal配合类型转换器既能匹配NUMERIC亲和性,还能避免浮点数精度丢失:
- 定义类型转换器
class BigDecimalConverter { @TypeConverter fun decimalToDouble(value: BigDecimal?): Double? { return value?.toDouble() } @TypeConverter fun doubleToDecimal(value: Double?): BigDecimal? { return value?.let { BigDecimal(it.toString()) } } }
- 修改Room实体
在实体上添加@TypeConverters注解,将value字段类型改为BigDecimal,并指定typeAffinity为ColumnInfo.NUMERIC:
@Entity(tableName = "charges") @TypeConverters(BigDecimalConverter::class) data class Charge( @PrimaryKey val chargeId: Int, val name: String, val nameOnBill: String?, val chargeType: String?, @ColumnInfo(name = "value", typeAffinity = ColumnInfo.NUMERIC) val value: BigDecimal, val isActive: Boolean )
这样Room会将该字段识别为NUMERIC亲和性,与预打包数据库中的decimal(13,4)字段完全匹配,不会再触发亲和性校验错误。
方法二:强制关闭Room的预打包数据库校验(不推荐)
如果必须保留Double类型,可以通过自定义SQLiteOpenHelper跳过Room的亲和性校验,但此方法存在风险(可能隐藏数据库结构不匹配问题):
- 创建自定义
SupportSQLiteOpenHelper.Factory
class SkipAffinityCheckOpenHelperFactory(private val delegate: SupportSQLiteOpenHelper.Factory) : SupportSQLiteOpenHelper.Factory { override fun create(configuration: SupportSQLiteOpenHelper.Configuration): SupportSQLiteOpenHelper { val helper = delegate.create(configuration) return object : SupportSQLiteOpenHelper by helper { override fun onCreate(db: SupportSQLiteDatabase) { helper.onCreate(db) } override fun onUpgrade(db: SupportSQLiteDatabase, oldVersion: Int, newVersion: Int) { helper.onUpgrade(db, oldVersion, newVersion) } override fun onOpen(db: SupportSQLiteDatabase) { helper.onOpen(db) } } } }
- 在Room数据库构建时使用该Factory
@Database(entities = [Charge::class], version = 1, exportSchema = false) abstract class AppDatabase : RoomDatabase() { abstract fun chargeDao(): ChargeDao companion object { fun getInstance(context: Context): AppDatabase { return Room.databaseBuilder(context, AppDatabase::class.java, "app_db") .openHelperFactory(SkipAffinityCheckOpenHelperFactory(Room.getDatabaseBuilder(context, AppDatabase::class.java, "app_db").openHelperFactory!!)) .createFromAsset("your_prepackaged_db.db") .build() } } }
注意:仅在确认预打包数据库结构完全符合业务需求时使用此方法,否则可能导致数据读写异常。
内容的提问来源于stack exchange,提问作者Syed Hussain Mehdi
相关产品推荐
相关产品推荐

