最近使用Room进行版本提升,要在表中删除一条字段。新增字段的方式之前已经使用过了:
val goodsDatabase = Room.databaseBuilder(
context.applicationContext,
GoodsDatabase::class.java,
"goods")
.allowMainThreadQueries()
.addMigrations(object : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE stock_goods ADD goods_discount INTEGER NOT NULL DEFAULT 100")
})
.build()
很简单,利用migration可以通过sql语句在stock_goods 这个表中新增一个Integer类型的goods_discount字段,其中Migration(2, 3)中的2和3分别是当前数据库的版本和升级的数据库的版本。
然后我以为删除字段和新增字段一样,只要将sql语句改为“ALTER TABLE stock_goods DROP COLUMN goods_model”就可以了(goods_model是我要新增的字段)。结果直接提示错误,网上一查才知道原来room是不能直接删除数据库中的字段的,因此我们只能另外想办法了。
// 创建一个新的表并且复制数据到新表中
database.execSQL(
"CREATE TABLE new_stock_goods (goods_barcode TEXT NOT NULL," +
" goods_name TEXT NOT NULL, goods_price REAL NOT NULL, id INTEGER NOT NULL, goods_id TEXT NOT NULL," +
" shop_id INTEGER NOT NULL, count INTEGER NOT NULL, PRIMARY KEY(goods_barcode))"
)
// 复制旧表中的数据到新表之中
database.execSQL(
"INSERT INTO new_stock_goods(goods_barcode, goods_name, goods_price, id, goods_id, shop_id, count) " +
"SELECT goods_barcode, goods_name, goods_price, id, goods_id, shop_id, count FROM stockgoods"
)
// 删除旧表
database.execSQL("DROP TABLE IF EXISTS stockgoods")
// 修改新表的名称为旧表
database.execSQL("ALTER TABLE new_stock_goods RENAME TO stockgoods")
这是我参考网上博客得到的新方法,既然不能直接删除,那么就只能新建一个表了。
首先我们新建一个表,取名为new_stock_goods,然后定义各种字段,字段名称和旧表一致,只是旧表不要的goods_model我们就不要定义了。
然后我们将旧表中的数据复制到新表之中,goods_model的数据不需要复制。
复制完了之后我们就删除旧表,最后将新版的名字改成旧表的stock_goods ,这样下来就算完成了。
总的来说还是比较麻烦的,我现在表中的字段只有七八个,一个个写下来就有点麻烦了,要是再增加的话,更是一种折磨,不知道有没有更好的迁移方法,如果有大神知道,希望能告知一下。
另外说一下测试room数据迁移时遇到的坑:
我在上面创建新表的sql语句中,每一个字段后面都加了NOT NULL这句话,这是对数据库字段属性的声明。数据库每一个column都有notNull这个属性,在字段加了NOT NULL这句话之后,它对应的notNull就会等于true。如果我们不加的话,由于room通过@Entity注解默认创建的表中每一个字段的notNull都为true,因此如果在创建新表的字段后面不加NOT NULL,它的notNull就是false,那么就会出现java.lang.IllegalStateException: Migration didn't properly handle StockGoods的错误。
现在我将
database.execSQL(
"CREATE TABLE new_stock_goods (goods_barcode TEXT NOT NULL," +
" goods_name TEXT NOT NULL, goods_price REAL NOT NULL, id INTEGER NOT NULL, goods_id TEXT NOT NULL," +
" shop_id INTEGER NOT NULL, count INTEGER NOT NULL, PRIMARY KEY(goods_barcode))"
)
中goods_barcode后面的NOT NULL去掉,然后再执行,就出现了错误
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.hongyue.shopsystem/com.hongyue.shopsystem.ui.stock.activity.StockActivity}: java.lang.IllegalStateException: Migration didn't properly handle StockGoods(com.hongyue.shopsystem.mvp.model.bean.StockGoods).
Expected:
TableInfo{name='StockGoods', columns={goods_id=Column{name='goods_id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, goods_name=Column{name='goods_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, count=Column{name='count', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, shop_id=Column{name='shop_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_price=Column{name='goods_price', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='StockGoods', columns={goods_id=Column{name='goods_id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, count=Column{name='count', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_name=Column{name='goods_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, shop_id=Column{name='shop_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=1}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, goods_price=Column{name='goods_price', type='REAL', affinity='4', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=null}
该错误是由新表和@Entity注解的类对应的数据表格式不同导致的,对比上面的错误信息我们可以找到这么一点不同
Expected:
goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1}
Found:
goods_barcode=Column{name='goods_barcode', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=1}
其他的属性都一样,只有notNull不一样,这也是造成错误的原因,因此如果再出现java.lang.IllegalStateException: Migration didn't properly handle的错误,那么要仔细对比错误信息,看看到底是什么原因导致的,将对应的属性修改一样就可以了。