如何将无主键的SQLite表迁移至Room框架?
解决Room迁移时无主键的问题
这问题我之前在项目里也碰到过——Room对实体类的主键要求是硬性的,而SQLite确实不支持直接用ALTER TABLE给现有表添加主键(毕竟主键是表的核心约束,SQLite的表结构修改能力有限),不过有两种靠谱的解决思路,你可以根据自己的业务情况选:
方案一:用现有唯一字段作为主键(如果适用)
如果你的cache表中key字段的值是唯一不重复的,那最简单的办法就是直接把key设为Room实体的主键,这样不用修改原有表结构,只需要调整Entity类:
@Entity(tableName = "cache") public class Cache { @PrimaryKey // 把key标记为主键 public String key; public String content; public Integer time; }
不过要注意:如果原表中key存在重复值,这种方案会导致Room插入数据时报错,因为主键要求唯一。这种情况下就需要用第二种方案。
方案二:添加自增主键,通过表重建迁移
如果key不唯一,或者你就是想保留自增id的设计,那只能通过创建新表、迁移数据的方式来实现,具体步骤如下:
1. 修改Entity类,添加自增主键
@Entity(tableName = "cache") public class Cache { @PrimaryKey(autoGenerate = true) // 标记为自增主键 public Integer id; public String key; public String content; public Integer time; }
2. 编写Room迁移逻辑
创建一个Migration类,实现从旧版本到新版本的表迁移:
static final Migration MIGRATION_OLD_TO_NEW = new Migration(1, 2) { @Override public void migrate(SupportSQLiteDatabase database) { // 1. 创建包含主键的新表 database.execSQL( "CREATE TABLE cache_new (id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT, content TEXT, time INTEGER)" ); // 2. 将旧表的数据迁移到新表(id会自动生成) database.execSQL( "INSERT INTO cache_new (key, content, time) SELECT key, content, time FROM cache" ); // 3. 删除旧表 database.execSQL("DROP TABLE cache"); // 4. 把新表重命名为原表名 database.execSQL("ALTER TABLE cache_new RENAME TO cache"); } };
注意:这里的版本号
1和2要对应你的数据库版本——旧版本号是你之前的数据库版本,新版本号是修改后的版本号,记得在@Database注解里同步更新版本号。
3. 在Room数据库构建时添加迁移
创建RoomDatabase实例时,把上面的迁移类加进去:
Room.databaseBuilder(context.getApplicationContext(), YourCacheDatabase.class, "cache-db") .addMigrations(MIGRATION_OLD_TO_NEW) .build();
补充说明
为什么SQLite不能直接加主键?因为SQLite的ALTER TABLE只支持添加列、重命名表等有限的结构修改操作,而添加主键属于修改表的核心约束,不在支持范围内,所以必须通过重建表的方式来实现。
内容的提问来源于stack exchange,提问作者liuyong
相关产品推荐
相关产品推荐

