我发现在进行房间数据库迁移时,注释@SerializedName 和@ColumnInfo 中提供的字段名称必须匹配,无论是自动迁移还是手动迁移。这是真的还是我遗漏了什么?
为了代码的缘故,我展示了一个 AutoMigration,但我也将其设置为手动迁移并收到了同样的问题。
数据库设置。
@Database(
version = 30,
entities = [
...
MobileService::class,
...
],
exportSchema = true,
autoMigrations = [
AutoMigration(from = 29, to = 30)
]
)
实体类。
注意@SerializedName 与@ColumnInfo 中为我尝试添加的新列提供的字段名称之间的区别。数据将从 API 调用中获取,因此我希望 SerializedName 为“scac”,以便在读取传入的 json 时正确映射。我希望@ColumnInfo 是“primary_scac”,因为我们将有另一个带有字段“scac”的表。
@Entity(tableName = "mobile_service")
data class MobileService(
@PrimaryKey(autoGenerate = false)
@SerializedName("id")
@ColumnInfo(name = "id")
val id: Int = 0,
...
@SerializedName("legal_terms_name")
@ColumnInfo(name = "legal_terms_name")
val legalTermsName: String? = null,
// NEW COLUMN ADDED HERE
@SerializedName("scac")
@ColumnInfo(name = "parent_scac")
val parentScac: String? = null,
@SerializedName("dr_contact_email")
@ColumnInfo(name = "dr_contact_email")
val drContactEmail: String? = null,
...
)
尝试从 29 迁移到 30 会产生堆栈跟踪。下面是它的一个片段。随意浏览它,但据我所见,新列信息在“预期”TableInfo 中找到,而在“已找到”中不存在。
Caused by: java.lang.IllegalStateException: Migration didn't properly handle: mobile_service(com.tms.android.data.ms.MobileService).
Expected: 2023-02-22 11:23:27.337 17960-17960 AndroidRuntime com.tms.android.appname E TableInfo{name='mobile_service', columns={legal_terms_name=Column{name='legal_terms_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, driver_arrived_flag=Column{name='driver_arrived_flag', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_equip_issues=Column{name='ping_equip_issues', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, apns_password=Column{name='apns_password', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, enable_location_rating=Column{name='enable_location_rating', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, max_search=Column{name='max_search', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, ping_birthday=Column{name='ping_birthday', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_email_list=Column{name='dr_email_list', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_time_off_feature=Column{name='allow_time_off_feature', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, mobile_branding_id=Column{name='mobile_branding_id', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, dr_contact_phone=Column{name='dr_contact_phone', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, require_order_term=Column{name='require_order_term', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_contact_name=Column{name='dr_contact_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, ping_hiredate=Column{name='ping_hiredate', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, qualcom_enable=Column{name='qualcom_enable', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_physical_expire=Column{name='ping_physical_expire', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, use_relay=Column{name='use_relay', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, enable_raterequest=Column{name='enable_raterequest', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, allow_driver_password_reset=Column{name='allow_driver_password_reset', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, parent_scac=Column{name='parent_scac', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, login_expire=Column{name='login_expire', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, gcm_sender_key=Column{name='gcm_sender_key', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_geotab_sso=Column{name='allow_geotab_sso', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_mvr_expire=Column{name='ping_mvr_expire', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, enable_bol_prompt=Column{name='enable_bol_prompt', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, driver_settlement_flag=Column{name='driver_settlement_flag', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_response=Column{name='dr_response', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, require_legal_term=Column{name='require_legal_term', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, time_off_event_code=Column{name='time_off_event_code', type='TEXT', affinity='2', no 2023-02-22 11:23:27.337 17960-17960 AndroidRuntime com.tms.android.appname E tNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_driver_rec=Column{name='allow_driver_rec', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_license_expire=Column{name='ping_license_expire', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, proof_of_delivery=Column{name='proof_of_delivery', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, allow_driver_history_report=Column{name='allow_driver_history_report', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_contact_email=Column{name='dr_contact_email', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_driver_dlvr_receipts=Column{name='allow_driver_dlvr_receipts', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found: 2023-02-22 11:23:27.338 17960-17960 AndroidRuntime com.tms.android.appname E TableInfo{name='mobile_service', columns={legal_terms_name=Column{name='legal_terms_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, driver_arrived_flag=Column{name='driver_arrived_flag', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_equip_issues=Column{name='ping_equip_issues', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, apns_password=Column{name='apns_password', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, enable_location_rating=Column{name='enable_location_rating', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, max_search=Column{name='max_search', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, ping_birthday=Column{name='ping_birthday', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_email_list=Column{name='dr_email_list', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_time_off_feature=Column{name='allow_time_off_feature', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, mobile_branding_id=Column{name='mobile_branding_id', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, dr_contact_phone=Column{name='dr_contact_phone', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, require_order_term=Column{name='require_order_term', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_contact_name=Column{name='dr_contact_name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, ping_hiredate=Column{name='ping_hiredate', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, qualcom_enable=Column{name='qualcom_enable', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_physical_expire=Column{name='ping_physical_expire', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, use_relay=Column{name='use_relay', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, enable_raterequest=Column{name='enable_raterequest', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, allow_driver_password_reset=Column{name='allow_driver_password_reset', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, login_expire=Column{name='login_expire', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, gcm_sender_key=Column{name='gcm_sender_key', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_geotab_sso=Column{name='allow_geotab_sso', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_mvr_expire=Column{name='ping_mvr_expire', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, enable_bol_prompt=Column{name='enable_bol_prompt', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, driver_settlement_flag=Column{name='driver_settlement_flag', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_response=Column{name='dr_response', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, require_legal_term=Column{name='require_legal_term', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, time_off_event_code=Column{name='time_off_event_code', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_driver_rec=Column{name='allow_driver_rec', type='TEXT', affini 2023-02-22 11:23:27.338 17960-17960 AndroidRuntime com.tms.android.appname E ty='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, ping_license_expire=Column{name='ping_license_expire', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, proof_of_delivery=Column{name='proof_of_delivery', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, allow_driver_history_report=Column{name='allow_driver_history_report', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, dr_contact_email=Column{name='dr_contact_email', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, allow_driver_dlvr_receipts=Column{name='allow_driver_dlvr_receipts', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:103) at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:183)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:416)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:151)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:112)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:706)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:483)
at androidx.room.RoomDatabase.query(RoomDatabase.java:526)
at androidx.room.util.DBUtil.query(DBUtil.java:86) at com.tms.android.data.settings.SettingsDao_Impl$7.call(SettingsDao_Impl.java:201)
at com.tms.android.data.settings.SettingsDao_Impl$7.call(SettingsDao_Impl.java:198)
at androidx.room.CoroutinesRoom$Companion$execute$4$job$1.invokeSuspend(CoroutinesRoom.kt:88)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
使字段名称在 SerializedName 和 ColumnInfo 注释中匹配导致预期的迁移成功运行。
@SerializedName("scac")
@ColumnInfo(name = "scac")
val parentScac: String? = null,
为了了解房间迁移的“陷阱”,我试图理解为什么会这样。我们的应用程序还不需要进行任何迁移,因为我们现在还没有上架。很长一段时间以来,我们一直愉快地进行破坏性迁移,现在是时候开始跟踪更改,而不是出于简单原因擦除整个数据库。