You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Room数据库迁移异常:appointment表未正确处理问题求助

Android Room迁移错误修复:Migration didn't properly handle appointment实体

错误概述

使用Android Room数据库时触发以下错误:

java.lang.IllegalStateException: Migration didn't properly handle: appointment(com.example.spaappointment.data.Appointment).

错误日志显示:Room预期appointment表包含完整字段,但实际检测到表为空(columns={})。

Appointment实体类代码

package com.example.spaappointment.data

import androidx.annotation.NonNull
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "appointment")
data class Appointment(
    @NonNull @PrimaryKey
    val date: String,

    @ColumnInfo
    val name: String,

    @NonNull
    @ColumnInfo
    val phonenumber: Int,

    @NonNull
    @ColumnInfo
    val email: String,

    @ColumnInfo
    val note: String
)

数据库Schema(版本3)

{
  "formatVersion": 1,
  "database": {
    "version": 3,
    "identityHash": "939188bd3f343aa9fe8319733e41e36a",
    "entities": [
      {
        "tableName": "service",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`price`TEXT NOT NULL,`name`TEXT NOT NULL,`description`TEXT NOT NULL,`id` INTEGER NOT NULL, PRIMARY KEY(`id`))",
        "fields": [
          {
            "fieldPath": "price",
            "columnName": "price",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "description",
            "columnName": "description",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": ["id"],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "appointment",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date`TEXT NOT NULL,`name`TEXT NOT NULL,`phonenumber`INTEGER NOT NULL,`email`TEXT NOT NULL,`note` TEXT NOT NULL, PRIMARY KEY(`date`))",
        "fields": [
          {
            "fieldPath": "date",
            "columnName": "date",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "phonenumber",
            "columnName": "phonenumber",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "email",
            "columnName": "email",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "note",
            "columnName": "note",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": ["date"],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '939188bd3f343aa9fe8319733e41e36a')"
    ]
  }
}

完整错误日志

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.spaappointment, PID: 9952
java.lang.IllegalStateException: Migration didn't properly handle: appointment(com.example.spaappointment.data.Appointment).
Expected:
TableInfo{name='appointment', columns={date=Column{name='date', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, name=Column{name='name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, phonenumber=Column{name='phonenumber', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, note=Column{name='note', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, email=Column{name='email', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='appointment', columns={}, foreignKeys=[], indices=[]}

修复方案

1. 补全迁移脚本中的表创建逻辑

检查你的Migration类,确保对应版本升级时执行了appointment表的创建语句,语句需和Schema中的createSql完全一致:

val MIGRATION_2_3 = object : Migration(2, 3) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // 确保创建appointment表的语句与Schema完全匹配
        database.execSQL("""
            CREATE TABLE IF NOT EXISTS `appointment` (
                `date` TEXT NOT NULL,
                `name` TEXT NOT NULL,
                `phonenumber` INTEGER NOT NULL,
                `email` TEXT NOT NULL,
                `note` TEXT NOT NULL,
                PRIMARY KEY(`date`)
            )
        """)
        // 如果还有其他表的变更,也要添加对应SQL
    }
}

2. 确认数据库配置正确

  • 在RoomDatabase子类中,确保版本号设置为3,并且注册了迁移脚本:
@Database(entities = [Appointment::class, Service::class], version = 3)
abstract class SpaDatabase : RoomDatabase() {
    // 定义DAO接口
    abstract fun appointmentDao(): AppointmentDao
    abstract fun serviceDao(): ServiceDao
}
  • 初始化数据库时必须添加迁移脚本:
val db = Room.databaseBuilder(
    context.applicationContext,
    SpaDatabase::class.java,
    "spa_database"
)
.addMigrations(MIGRATION_2_3) // 注册迁移脚本
.build()

3. 排查是否误删表

检查迁移代码中是否存在DROP TABLE appointment之类的语句,若有则移除,避免表被意外删除。

4. 开发环境临时方案(数据会丢失)

如果是开发阶段,可使用破坏性迁移快速验证,Room会删除旧数据库并重建新的:

val db = Room.databaseBuilder(...)
.fallbackToDestructiveMigration()
.build()

内容的提问来源于stack exchange,提问作者Duaa Alyamani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:45:30