@SerializedName 和@ColumnInfo 注解在 Room 数据库迁移时冲突?

问题描述 投票:0回答:0

我发现在进行房间数据库迁移时,注释@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,

为了了解房间迁移的“陷阱”,我试图理解为什么会这样。我们的应用程序还不需要进行任何迁移,因为我们现在还没有上架。很长一段时间以来,我们一直愉快地进行破坏性迁移,现在是时候开始跟踪更改,而不是出于简单原因擦除整个数据库。

android android-room database-migration
© www.soinside.com 2019 - 2024. All rights reserved.